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.
- 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
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
}
}