### Dictionary Fundamentals

A Dictionary, provided by Foundation, is a type of hash table that stores key/value pairs.

• Keys must conform to Hashable
• 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

### 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
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",

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
3 friends are named John
2 friends are named Mary
1 friends are named Sam``````

Related functional commands available to Dictionary:

### Iterate over dictionary contents sorted by value

``````let friends = ["John", "Mary", "Sam",

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 Sam``````

### Inspect Dictionary values for existince of combination of key/value

``````let friends = ["John", "Mary", "Sam",

let friendsCount = Dictionary(
friends.map { (\$0, 1) },
uniquingKeysWith: +)

let isPresent = friendsCount.contains {
\$0.key == "John" && \$0.value == 3 }

// isPresent = true``````

Related searching routines:

### 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
}
}``````