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.

  1. Use map over an array to create a tuple for each array element
  2. 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    }