Swift Dictionary Cheat Sheet
Dictionary Fundamentals
A Dictionary, provided by Foundation, is a type of hash table that stores key/value pairs.
- Keys must conform to Hashable
- Access to elements is O(1)
- Derived from NSDictionary
Best used for key/value storage where lookup by key is the primary use case. However, Apple has added a lot of handy routines to Dictionary that make it useful for many types of data processing and analysis out of the box.
Create an Empty Dictionary
1 var empty:[Int:String] = [:]
Create using Type Inference
1 var population = [String: Int]()
Accessing the value of a key
Values are optional, because keys may or may not exist
1 var population = [String: Int]()
2
3 population["us"] = 350_000_000
4
5 print(population["us"]) // Optional(350000000)
6 print(population["fr"]) // nil
Check for Key Existence
1 var population = [String: Int]()
2
3 population["us"] = 350_000_000
4
5 print(population.keys.contains("us")) // true
Use a struct as the key
To use a struct as a key, declare the struct Hashable. If all members of the struct already conform to Hashable, all properties will be used as the hash key. If not, follow the template for using a class as the key (below)
1 struct Country : Hashable {
2 let name : String
3 let iso : String
4 }
5
6 var country: [Country : Int] = [:]
7
8 let usa = Country(name: "United States", iso: "us")
9
10 country[usa] = 1
11 country[usa] = (country[usa] ?? 0) + 1
12
13 print(country[usa] ?? 0) // 2
Using a class as the key
Classes do not automatically synthesize Equatable or Hashable, so implement these conformances manually before using the class as a Dictionary key.
1 class Country {
2 let name : String
3 let iso : String
4
5 init(name: String, iso: String) {
6 self.name = name
7 self.iso = iso
8 }
9 }
10
11 extension Country : Equatable {
12 static func == (lhs: Country, rhs: Country) -> Bool {
13 return lhs.iso == rhs.iso
14 }
15 }
16
17 extension Country : Hashable {
18 func hash(into hasher: inout Hasher) {
19 hasher.combine(iso) // iso itself is a reasonable hash key
20 }
21 }
22
23 var countries = [Country : Int]()
24
25 let usa = Country(name: "United States", iso: "us")
26
27 countries[usa] = 1
28 countries[usa] = (countries[usa] ?? 0) + 1
29
30 print(countries[usa] ?? 0) // 2
Use a Dictionary to count the frequency of values in an array
Dictionary and functional programming can be used to create a frequency table in a single line of code.
- Use map over an array to create a tuple for each array element
- Use Dictionary's uniquingKeysWith to create a count of keys, storing the result in a dictionary
1 let friends = ["John", "Mary", "Sam", "John", "Adam", "John"]
2
3 let friendsNameCount = Dictionary(
4 friends.map { ($0, 1) },
5 uniquingKeysWith: +)
6
7 print(friendsNameCount) // ["John": 3, "Mary": 1, "Sam": 1, "Adam": 1]
8
9 print(friendsNameCount["John"]) // Optional(3)
Get a sorted list of keys
1 let friends = ["John", "Mary", "Sam", "John", "Adam", "John"]
2 let friendsNameCount = Dictionary(friends.map { ($0, 1) }, uniquingKeysWith: +)
3
4 print(friendsNameCount.keys.sorted(by: <))
5
6 // output
7 ["Adam", "John", "Mary", "Sam"]
Iterate over dictionary contents in no specific order
1 let friends = ["John", "Mary", "Sam", "John", "Adam", "John"]
2
3 let friendsNameCount = Dictionary(friends.map { ($0, 1) }, uniquingKeysWith: +)
4
5 for (name, frequency) in friendsNameCount {
6 print("\(frequency) friends are named \(name) ")
7 }
8
9 // output
10 3 friends are named John
11 1 friends are named Sam
12 1 friends are named Adam
13 1 friends are named Mary
Iterate over dictionary contents sorted by key #1
One way to access elements by sorted keys is to fetch the keys, sort the keys, and then use the keys to access the underlying objects.
1 let friends = ["John", "Mary", "Sam", "John", "Adam", "John"]
2
3 let friendsNameCount = Dictionary(friends.map { ($0, 1) }, uniquingKeysWith: +)
4
5 let sortedNames = friendsNameCount.keys.sorted(by: <)
6
7 for name in sortedNames {
8 print("\(friendsNameCount[name]!) friends are named \(name) ")
9 }
10
11 // output
12 1 friends are named Adam
13 3 friends are named John
14 1 friends are named Mary
15 1 friends are named Sam
Iterate over dictionary contents sorted by key #2
A more concise way to accomplish the previous example is to use the Dictionary sorted command to return an array of dictionary contents.
1 let friends = ["John", "Mary", "Sam",
2 "John", "Adam", "John", "Mary"]
3
4 let friendsCount = Dictionary(
5 friends.map { ($0, 1) },
6 uniquingKeysWith: +)
7
8 let sortedByFrequency =
9 friendsCount.sorted { $0.key < $1.key }
10
11 for (name, frequency) in sortedByFrequency {
12 print("\(frequency) friends are named \(name)")
13 }
14
15 // output
16 1 friends are named Adam
17 3 friends are named John
18 2 friends are named Mary
19 1 friends are named Sam
Related functional commands available to Dictionary:
map, compactMap, mapValues, compactMapValues, reduce, flatMap, shuffled
Iterate over dictionary contents sorted by value
1 let friends = ["John", "Mary", "Sam",
2 "John", "Adam", "John", "Mary"]
3
4 let friendsCount = Dictionary(
5 friends.map { ($0, 1) },
6 uniquingKeysWith: +)
7
8 let sortedByFrequency =
9 friendsCount.sorted { $0.value > $1.value }
10
11 for (name, frequency) in sortedByFrequency {
12 print("\(frequency) friends are named \(name)")
13 }
14
15 // output
16 3 friends are named John
17 2 friends are named Mary
18 1 friends are named Adam
19 1 friends are named Sam
Inspect Dictionary values for existince of combination of key/value
1 let friends = ["John", "Mary", "Sam",
2 "John", "Adam", "John", "Mary"]
3
4 let friendsCount = Dictionary(
5 friends.map { ($0, 1) },
6 uniquingKeysWith: +)
7
8 let isPresent = friendsCount.contains {
9 $0.key == "John" && $0.value == 3 }
10
11 // isPresent = true
Related searching routines:
allSatisfy, first, firstIndex, min, max
Convert a Dictionary to a JSON string
It's possible to leverage the Dictionary encode function to return a dictionary's contents as a JSON string. This may be of limited practical value, since the format of the JSON is limited, but can be handy in certain scenarios.
1 struct Friend : Codable, CustomStringConvertible {
2 let name: String
3 let age: Int
4
5 var description: String {
6 return "\(name)"
7 }
8 }
9
10 let friends = [
11 "John" : Friend(name: "John", age: 21),
12 "Mary" : Friend(name: "Mary", age: 31),
13 "Josh" : Friend(name: "Josh", age: 21),
14 ]
15
16
17 let encodedDict = try JSONEncoder().encode(friends)
18
19 // Output
20 {
21 "Mary": {
22 "name": "Mary",
23 "age": 31
24 },
25 "Josh": {
26 "name": "Josh",
27 "age": 21
28 },
29 "John": {
30 "name": "John",
31 "age": 21
32 }
33 }