Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift array reduction: cannot use mutating member on immutable value

I have the following code that attempts to consolidate redundant elements of an array:

var items : [String] = ["hello", "world", "!", "hello"]

var mutableSet = Set<String>()

items.reduce(mutableSet, combine: { (set: Set<String>, element: String) in
    return set.insert(element)
})

set.insert(element) gives me the error Cannot use mutating member on immutable value: 'set' is a 'let' constant. What's wrong and how can I fix it?

like image 405
raphaelrk Avatar asked Jun 30 '26 02:06

raphaelrk


2 Answers

The problem with the OP's code is that the accumulator in the reduce is immutable so it won't allow you to use the mutating function insert().

A tidy solution is to define an non-mutating equivalent to insert() called inserting() in an extension to Set as follows.

extension Set {
    //returns a new set with the element inserted
    func inserting(_ element: Element) -> Set<Element> {
        var set = self
        set.insert(element)
        return set
    }
}

Now we can write the reduce as follows

var items : [String] = ["hello", "world", "!", "hello"]

let set = items.reduce(Set<String>()){ accumulator, element in
    accumulator.inserting(element)
}
like image 128
Robert Muckle-Jones Avatar answered Jul 03 '26 08:07

Robert Muckle-Jones


In Swift, collections are value types. Value-typed variables declared with let (as implicitly are function parameters) cannot be modified. Additionally, your closure returns nothing, so reduce will probably not succeed.

I believe that reduce is not the best-suited tool for this task. Consider this for loop instead:

var set = Set<String>()
for element in items { set.insert(element) }

Another even simpler option would be to use the unionInPlace method:

var set = Set<String>()
set.unionInPlace(items)

Even better perhaps, create the set straight from the collection:

var set = Set<String>(items)
like image 45
zneak Avatar answered Jul 03 '26 08:07

zneak