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

    var empty:[Int:String] = [:]

Create using Type Inference

    var population = [String: Int]()

Accessing the value of a key

Values are optional, because keys may or may not exist

    var population = [String: Int]()
    
    population["us"] = 350_000_000
    
    print(population["us"])  // Optional(350000000)
    print(population["fr"])  // nil

Check for Key Existence

    var population = [String: Int]()
    
    population["us"] = 350_000_000
    
    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)

    struct Country : Hashable {
       let name : String
       let iso : String
    }
    
    var country: [Country : Int] = [:]
        
    let usa = Country(name: "United States", iso: "us")
    
    country[usa] = 1
    country[usa] = (country[usa] ?? 0) + 1  
    
    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.

    class Country {
        let name : String
        let iso : String
    
        init(name: String, iso: String) {
            self.name = name
            self.iso = iso
        }
    }
    
    extension Country : Equatable {
        static func == (lhs: Country, rhs: Country) -> Bool {
            return lhs.iso == rhs.iso
        }
    }
    
    extension Country : Hashable {
        func hash(into hasher: inout Hasher) {
            hasher.combine(iso)  // iso itself is a reasonable hash key
        }
    }
    
    var countries = [Country : Int]()
    
    let usa = Country(name: "United States", iso: "us")
    
    countries[usa] = 1
    countries[usa] = (countries[usa] ?? 0) + 1
    
    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
    let friends = ["John", "Mary", "Sam", "John", "Adam", "John"]
    
    let friendsNameCount = Dictionary(
                              friends.map { ($0, 1) }, 
                              uniquingKeysWith: +)
    
    print(friendsNameCount) // ["John": 3, "Mary": 1, "Sam": 1, "Adam": 1]
    
    print(friendsNameCount["John"]) // Optional(3)

Get a sorted list of keys

    let friends = ["John", "Mary", "Sam", "John", "Adam", "John"]
    let friendsNameCount = Dictionary(friends.map { ($0, 1) }, uniquingKeysWith: +)
    
    print(friendsNameCount.keys.sorted(by: <))
    
    // output
    ["Adam", "John", "Mary", "Sam"]

Iterate over dictionary contents in no specific order

    let friends = ["John", "Mary", "Sam", "John", "Adam", "John"]
    
    let friendsNameCount = Dictionary(friends.map { ($0, 1) }, uniquingKeysWith: +)
    
    for (name, frequency) in friendsNameCount {
        print("\(frequency) friends are named \(name) ")
    }
    
    // output
    3 friends are named John 
    1 friends are named Sam 
    1 friends are named Adam 
    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.

    let friends = ["John", "Mary", "Sam", "John", "Adam", "John"]
    
    let friendsNameCount = Dictionary(friends.map { ($0, 1) }, uniquingKeysWith: +)
    
    let sortedNames = friendsNameCount.keys.sorted(by: <)
    
    for name in sortedNames {
        print("\(friendsNameCount[name]!) friends are named \(name) ")
    }
    
    // output
    1 friends are named Adam 
    3 friends are named John 
    1 friends are named Mary 
    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.

    let friends = ["John", "Mary", "Sam",
                   "John", "Adam", "John", "Mary"]
                   
    let friendsCount = Dictionary(
                         friends.map { ($0, 1) },
                         uniquingKeysWith: +)
    
    let sortedByFrequency =
        friendsCount.sorted { $0.key < $1.key }
    
    for (name, frequency) in sortedByFrequency {
        print("\(frequency) friends are named \(name)")
    }
    
    // output
    1 friends are named Adam
    3 friends are named John
    2 friends are named Mary
    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

    let friends = ["John", "Mary", "Sam",
                   "John", "Adam", "John", "Mary"]
                   
    let friendsCount = Dictionary(
                         friends.map { ($0, 1) },
                         uniquingKeysWith: +)
    
    let sortedByFrequency =
        friendsCount.sorted { $0.value > $1.value }
    
    for (name, frequency) in sortedByFrequency {
        print("\(frequency) friends are named \(name)")
    }
    
    // output
    3 friends are named John
    2 friends are named Mary
    1 friends are named Adam
    1 friends are named Sam

Inspect Dictionary values for existince of combination of key/value

    let friends = ["John", "Mary", "Sam", 
                   "John", "Adam", "John", "Mary"]
                   
    let friendsCount = Dictionary(
                         friends.map { ($0, 1) }, 
                         uniquingKeysWith: +)
    
    let isPresent = friendsCount.contains { 
                          $0.key == "John" && $0.value == 3 }
    
    // 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.

    struct Friend : Codable,  CustomStringConvertible {
        let name: String
        let age: Int
        
        var description: String {
            return "\(name)"
        }
    }
    
    let friends = [
        "John" : Friend(name: "John", age: 21),
        "Mary" : Friend(name: "Mary", age: 31),
        "Josh" : Friend(name: "Josh", age: 21),
    ]
    
    
    let encodedDict = try JSONEncoder().encode(friends)
    
    // Output
    {
        "Mary": {
            "name": "Mary",
            "age": 31
        },
        "Josh": {
            "name": "Josh",
            "age": 21
        },
        "John": {
            "name": "John",
            "age": 21
        }
    }