shravan.sukumar
shravan.sukumar

Reputation: 121

Not able to add values to a dictionary

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

Answers (4)

dfrib
dfrib

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

Alexander
Alexander

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

Vatsal
Vatsal

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

Code Different
Code Different

Reputation: 93181

Try this:

for (key, value) in dictionary {
    dictionary.updateValue(value + [nameText], forKey: key)
}

Upvotes: 0

Related Questions