Overwriting with the subscript
You change the value stored under a key with the subscript, using the same syntax that adds a new entry. If the key already exists, its value is replaced. If not, a new pair is added.
var scores = [String: Int]()
scores["Alice"] = 95
scores["Bob"] = 87
scores["Alice"] = 99
scores["Charlie"] = 72
print(scores["Alice"]!, scores.count)
99 3
The assignment to "Alice" replaced 95 with 99 and did not add an entry, and the assignment to "Charlie" added one. Swift does not distinguish the two cases in the syntax, so the count shows which happened.
As with every change to a dictionary, the dictionary must be declared with var. On a let dictionary the assignment is a compile error.
Getting the old value back
The method updateValue(_:forKey:) also sets a value, and it returns what was stored before as an optional. The result is nil when the key was new:
let old = scores.updateValue(100, forKey: "Alice")
print(old as Any)
let first = scores.updateValue(1, forKey: "Zed")
print(first as Any)
Optional(99)
nil
Use it when you need the previous value. Otherwise the subscript is shorter.
Changing a value relative to its old one
For counters, combine the subscript with a default. The expression scores["Charlie", default: 0] += 5 reads the current value, or 0 when the key is missing, adds 5 and stores the result:
scores["Charlie", default: 0] += 5
scores["New", default: 0] += 5
print(scores["Charlie"]!, scores["New"]!)
77 5
Removing an entry
Assigning nil through the subscript deletes the pair. The method removeValue(forKey:) does the same and returns the removed value.
scores["Bob"] = nil
print(scores["Bob"] as Any)
nil
Updating while reading
When the new value depends on the old one and the key must already exist, combine if let with an assignment:
var m = ["a": 1]
if let old = m["a"] {
m["a"] = old + 1
}
print(m)
["a": 2]
The assignment only runs when the key is present, so a missing key is left alone instead of being created. Updating a copy never changes the original, because dictionaries are value types: after var s = scores, changing s does not touch scores.
Updating every value
To change all the values, loop over the pairs and assign each one back through its key. The loop works on the dictionary as it was when the loop began, so assigning inside it is safe:
var scores = ["Alice": 95, "Bob": 87]
for (name, score) in scores {
scores[name] = score + 5
}
print(scores["Alice"]!, scores["Bob"]!)
100 92
When you want a changed copy instead, mapValues returns a new dictionary with the same keys and leaves the original as it was: d.mapValues { $0 + 1 } on ["Alice": 95] gives ["Alice": 96].
The exercise
The starter code has a var dictionary with two students. One step is needed:
- Reassign the value for
"Alice"to 99 withscores["Alice"] = 99. The key exists, so its old value, 95, is replaced.
var scores = ["Alice": 95, "Bob": 87]
scores["Alice"] = 99
Afterwards scores["Alice"] is 99 and "Bob" is unchanged at 87.
Common mistakes
- Using
let. A constant dictionary cannot be updated, so the compiler stops you before the program runs. Changelettovar. - Misspelling the key.
scores["alice"] = 99adds a new key, since keys are case-sensitive, and leaves"Alice"at 95. - Assigning the wrong type.
scores["Alice"] = "99"does not compile, because the values are integers. - Assigning
nilby accident. It deletes the key instead of clearing the value.
Key takeaways
dict[key] = valueinserts or replaces.updateValue(_:forKey:)does the same and returns the old value as an optional.dict[key, default: 0] += 1updates relative to the current value, anddict[key] = nilremoves the entry.
