Reputation: 121
I have a dictionary -> var dictionary = [String : [String]]()
and I want to append string values in the array of the dictionary. This is how I'm doing it
for (key, value) in dictionary {
dictionary.updateValue(value.append(nameText),forKey: "name")
}
Here, nameText
is a string, I'm getting an error saying,
Cannot use mutating member on immutable value: 'value' is a 'let' constant.
What am I doing wrong? Help would be much appreciated.
Upvotes: 0
Views: 115
Reputation: 73196
/* example setup */
var dictionary: [String: [String]] = ["foo": [], "bar": []]
let nameText = "foobar"
/* append the value of the 'nameText' immutable to each inner array */
dictionary.keys.forEach { dictionary[$0]?.append(nameText) }
/* ok! */
print(dictionary) // ["bar": ["foobar"], "foo": ["foobar"]]
As described in the following Q&A, however
..., it is good to be aware of the overhead of mutating "in place", especially if working performance tight applications. Taking the advice from the answer in the linked thread above, an alternative, more sensible and less copy-wasteful approach would be e.g.:
var dictionary: [String: [String]] = ["foo": [], "bar": []]
let nameText = "foobar"
dictionary.keys.forEach {
var arr = dictionary.removeValue(forKey: $0) ?? []
arr.append(nameText)
dictionary[$0] = arr
}
print(dictionary) // ["bar": ["foobar"], "foo": ["foobar"]]
Upvotes: 0
Reputation: 63321
Your first issue is that value
is a let
constant within your loop body. You must declare it as var
in order to mutate it.
Your second issue is that you're trying to use value.append(nameText)
as the value to set for the key. However, append()
mutates the array in place, and returns Void
.
Thirdly, don't use updateValue(forKey:)
. There's really no point. Use subscripting instead.
var dictionary = [
"a" : ["a"],
"b" : ["b", "b"],
"c" : ["c", "c", "c"],
]
let nameText = "foo"
for (key, var value) in dictionary {
value.append(nameText)
dictionary["name"] = value
}
Now, this gets your code to compile, but I'm highly skeptical this is really what you want to do. You'll be overwriting the value for the "name"
key on every iteration, meaning only the last iteration's value will persist. Furthermore, because Dictionary
doesn't have a defined ordering, this code has indeterminate behaviour. What are you actually trying to do?
Upvotes: 1
Reputation: 18181
Think about it for a second; value.append(nameText)
is an action. It returns Void
(the type for ... nothing!).
You want to update the value to something upon which an action has been performed.
Instead of manually making a temporary copy, modifying that, and then using it to update the value for some key, you can simply use subscripts and extensions:
What you want is:
extension Dictionary
{
public subscript(forceUnwrapping key: Key) -> Value
{
get
{
return self[key]!
}
set
{
self[key] = newValue
}
}
}
So, for a dictionary named dictionary
:
for key in dictionary.keys
{
dictionary[forceUnwrapping: key].append(nameText)
}
Specifically, dictionary[forceUnwrapping: key].append(nameText)
.
Upvotes: 0
Reputation: 93181
Try this:
for (key, value) in dictionary {
dictionary.updateValue(value + [nameText], forKey: key)
}
Upvotes: 0