Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

swift: modifying arrays inside dictionaries

How can I easily add elements to an array inside a dictionary? It's always complaining with could not find member 'append' or could not find an overload for '+='

var dict = Dictionary<String, Array<Int>>() dict["key"] = [1, 2, 3]  // all of these fail dict["key"] += 4 dict["key"].append(4) // xcode suggests dict["key"].?.append(4) which also fails dict["key"]!.append(4) dict["key"]?.append(4)  // however, I can do this: var arr = dict["key"]! arr.append(4) // this alone doesn't affect dict because it's a value type (and was copied) dict["key"] = arr 

if I just assign the array to a var, modify it and then reassign it to the dict, won't I be copying everything? that wouldn't be efficient nor elegant.

like image 801
maltalef Avatar asked Jul 02 '14 14:07

maltalef


People also ask

How do you update an array in Swift?

Swift Array – Replace Element To replace an element with another value in Swift Array, get the index of the match of the required element to replace, and assign new value to the array using the subscript.

Can a dictionary key have multiple values Swift?

In Swift, dictionaries are unordered collections that store multiple key-value pairs with each value being accessed via a corresponding unique key.

What are the differences between arrays and dictionaries in Swift?

Arrays are ordered collections of values. Sets are unordered collections of unique values. Dictionaries are unordered collections of key-value associations. Arrays, sets, and dictionaries in Swift are always clear about the types of values and keys that they can store.


2 Answers

Swift beta 5 has added this functionality, and you've nailed the new method in a couple of your attempts. The unwrapping operators ! and ? now pass through the value to either operators or method calls. That is to say, you can add to that array in any of these ways:

dict["key"]! += [4] dict["key"]!.append(4) dict["key"]?.append(4) 

As always, be careful about which operator you use -- force unwrapping a value that isn't in your dictionary will give you a runtime error:

dict["no-key"]! += [5]        // CRASH! 

Whereas using optional chaining will fail silently:

dict["no-key"]?.append(5)     // Did it work? Swift won't tell you... 

Ideally you'd be able to use the new null coalescing operator ?? to address this second case, but right now that's not working.


Answer from pre-Swift beta 5:

It's a quirk of Swift that it's not possible to do what you're trying to do. The issue is that the value of any Optional variable is in fact a constant -- even when forcibly unwrapping. If we just define an Optional array, here's what we can and can't do:

var arr: Array<Int>? = [1, 2, 3] arr[0] = 5 // doesn't work: you can't subscript an optional variable arr![0] = 5 // doesn't work: constant arrays don't allow changing contents arr += 4 // doesn't work: you can't append to an optional variable arr! += 4 arr!.append(4) // these don't work: constant arrays can't have their length changed 

The reason you're having trouble with the dictionary is that subscripting a dictionary returns an Optional value, since there's no guarantee that the dictionary will have that key. Therefore, an array in a dictionary has the same behavior as the Optional array, above:

var dict = Dictionary<String, Array<Int>>() dict["key"] = [1, 2, 3] dict["key"][0] = 5         // doesn't work dict["key"]![0] = 5        // doesn't work dict["key"] += 4           // uh uh dict["key"]! += 4          // still no dict["key"]!.append(4)     // nope 

If you need to change something in an array in the dictionary you'll need to get a copy of the array, change it, and reassign, like this:

if var arr = dict["key"] {     arr.append(4)     dict["key"] = arr } 

ETA: Same technique works in Swift beta 3, though constant arrays no longer allow changes to contents.

like image 133
Nate Cook Avatar answered Oct 01 '22 12:10

Nate Cook


The accepted answer bypasses the following much simpler possibility, which also works for older Swift versions:

var dict = Dictionary<String, Array<Int>>() dict["key"] = [1, 2, 3]  print(dict)  dict["key", default: [Int]()].append(4)  print(dict) 

This will print:

["key": [1, 2, 3]] ["key": [1, 2, 3, 4]] 

And this:

var dict = Dictionary<String, Array<Int>>() dict["key", default: [Int]()].append(4) print(dict) 

will print:

["key": [4]] 
like image 34
Werner Altewischer Avatar answered Oct 01 '22 12:10

Werner Altewischer