swift: modifying arrays inside dictionaries

Related searches

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.

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.

Collection Types — The Swift Programming Language (Swift 5.3), Arrays, sets, and dictionaries in Swift are always clear about the types of values and after it's created by adding, removing, or changing items in the collection. Arrays, dictionaries and sets make up the three main collection types in Swift.We’ve already talked about Arrays in a previous post, and in this article, we’re going to move on and look at the second of these collection types: Dictionaries.

As a simple workaround you can use a NSMutableArray:

import Foundation

var dict = Dictionary<String, NSMutableArray>()
dict["key"] = [1, 2, 3] as NSMutableArray
dict["key"]!.addObject(4)

I am using effectively such simple solution in my project:

https://github.com/gui-dos/Guigna/blob/5c02f7e70c8ee3b2265f6916c6cbbe5cd3963fb5/Guigna-Swift/Guigna/GuignaAppDelegate.swift#L1150-L1157

Working with Array and Dictionary Collections in Swift 3, How to create a dictionary, with literal syntax and initializers; How to modify dictionaries, by adding, removing and changing elements; How arrays� Modifying Dictionaries You can use updateValue(forKey:) method to add an existing value to a given key of the dictionary. This method returns an optional value of the dictionary's value type.

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]]

Dictionaries in Swift Explained – LearnAppMaking, In a mutable Dictionary instance, you can modify in place a value that you've values that are integer arrays, then sorts each array in-place in descending order. on the dictionary to get an immutable copy and then performs additional Swift� Arrays, sets, and dictionaries in Swift are always clear about the types of values and keys that they can store. This means that you cannot insert a value of the wrong type into a collection by mistake.

Here is what I was telling Nate Cook, in the comments for his quality answer. This is what I consider "easily [adding] elements to an array inside a dictionary":

dict["key"] = dict["key"]! + 4
dict["key"] = dict["key"] ? dict["key"]! + 4 : [4]

For now, we need to define the + operator ourselves.

@infix func +<T>(array: T[], element: T) -> T[] {
    var copy = array
    copy += element
    return copy
}

I think this version removes too much safety; maybe define it with a compound operator?

@infix func +<T>(array: T[]?, element: T) -> T[] {
    return array ? array! + element : [element]
}

dict["key"] = dict["key"] + 4

Finally, this is the cleanest I can get it, but I'm confused about how array values/references work in this example.

@assignment func +=<T>(inout array: T[]?, element: T) {
    array = array + element
}

dict["key"] += 5

Dictionary, How to modify/add array elements in Swift? You can modify elements of an array by using subscript syntax and assignment operator, i.e. you need to include index of the value you want to update within square brackets after the name of the array followed by the assignment operator and new value . How to modify dictionary elements in Swift? You can add elements of in dictionary by using subscript syntax. You need to include new key as the subscript index and assign a new value of the type as of Dictionary. Example 6: Setting elements in a dictionary

Use 'for in', for getting values from dictionary's inside array. Here's an example to help you

var a = ["x":["a","b","c"], "y":["d"]]

for b in a {
    print(b)
}

Output:

("x", ["d"])
("y", ["a", "b", "c"])

Swift Arrays: How to Use it and Why? (With Examples), Swift has two types of collections namely arrays and dictionaries for storing collections of values. An array stores an ordered list of values of the same type. Dictionaries store unordered collections of values of the same type. The insertion of the wrong type into an array is not possible.

Swift provides three collection types for storing collections of values. Here we will try to show the differences between them so you can easily decide which one to use in every situation. Array: Array is ordered collection so you can access any element inside it using its index. Arrays can contain duplicates.

For example, you can use this method on an array of integers to filter adjacent equal entries or count frequencies. This method is preferred over reduce(_: _:) for efficiency when the result is a copy-on-write type, for example an Array or a Dictionary.

Comments
  • No - subscripting a dictionary gives you back an Optional, so it's like you're working with the optional array in my first example.
  • I don't know why Apple didn't define the + operator for arrays. If you do it yourself, you can use dict["key"] = dict["key"]! + 4.
  • The += operator is defined, but only for mutable arrays. dict["key"]! is immutable (it can't have its length changed). When you use dict["key"] = dict["key"]! + 4 you're creating a brand new array and reassigning it to dict["key"] -- different than .append(4) or += 4.
  • I didn't say +=, I said +. Obviously you're going to be creating a new array when you "add to" an immutable array (e.g. your var arr = dict["key"]); Apple should be handling the logic in + and then copying it over to +=.
  • It's not without great sadness that I'm about to give you the green tick. Really, Apple? I hope if they don't redesign this bit of the language, they at least make a new language construct especially for this case. Anyway: I just tried the dict["key"] = dict["key"]!.append(4) bit in playground and I'm still getting the could not find member 'append' error. What gives?
  • That's right, since NSMutableArray is a class, unlike Swift's native arrays, which are defined as structs. In this implementation dict["key"]! is still immutable, but that doesn't matter because you can change an immutable class's underlying properties.
  • It does work and is a very simple and sensible workaround. I had already started to dream of NS*-less code, though :(
  • You have to initialise the array before you can append to it. Great Answer.
  • For what it's worth, it's an amazing workaround. Well, for someone like me who's still far from getting the nitty-gritty of swift, at least. I'd still be a little concerned about it copying stuff in the background and me forgetting it and using this in a tight loop where performance is very important...