Dictionaries are one of Swift's three primary collection types. Dictionaries store mappings between keys which are elements of one type and values which are elements of another type (possibly the same type as that of the keys).
Dictionary literals are written as a series of key: value
pairs, separated by commas, enclosed in square brackets. Empty dictionaries can be written by following the type name of the dictionary by a pair of parenthesis, e.g. [Int: String]()
, or, if the type can be determined from the context, as just a pair of square brackets surrounding a colon, [:]
. Type names for dictionaries are written in one of two ways: Dictionary<K, V>
or [K: V]
where K
is the type of the keys in the dictionary and V
is the type of the values. When creating an empty array, the type must be specified.
var addresses: Dictionary<String, String> = ["The Munsters": "1313 Mockingbird Lane", "The Simpsons": "742 Evergreen Terrace", "Buffy Summers": "1630 Revello Drive"]
var sequences: [String: [Int]] = ["Euler's totient": [1, 1, 2, 2, 4, 2, 6, 4], "Lazy caterer": [1, 2, 4, 7, 11, 16, 22, 29, 37], "Carmichael": [561, 1105, 1729, 2465, 2821, 6601, 8911, 10585, 15841]]
let constants = ["pi": 3.14159, "e": 2.71828, "phi": 1.618033, "avogadro": 6.02214076e22]
var emptyDict1: [Int: Int] = [:]
var emptyDict2 = [Character: String]()
var emptyDict3 = Dictionary<Int, Double>()
Elements of a dictionary can be accessed using subscript notation, where the name of the dictionary is followed by square brackets which enclose the key for which we want the corresponding value.
Note, however, that the value returned is not of type Value, but rather of optional type, Value?. This is because one can supply a key that is not present in the dictionary. In these cases, Swift chooses to return nil
rather than throw an error.
let munster: String? = addresses["The Munsters"]
// => "1313 Mockingbird Lane"
let carmichael = sequences["Carmichael"]
// => [561, 1105, 1729, 2465, 2821, 6601, 8911, 10585, 15841]
let planck = constants["planck"]
// => nil
To avoid the optional type of the return, one can supply a default value to return if the key if not found in the dictionary.
let e: Double = constants["e", default: 0]
// => 2.71828
let hoagie: [Int] = sequences["Hoagie", default: []]
// => []
let betty = addresses["Betty Cooper", default: "Address unknown"]
// => "Address unknown"
This subscript notation can be used to retrieve the value associated with that key as well as to set the value associated with that key, provided the dictionary was defined as a variable (i.e. using var
). This can be used to update the value associated with a key or to add a new key: value pair to the dictionary.
sequence["Euler's totient"]?.append(contentsOf: [6,4])
sequence["Euler's totient"]
// => [1, 1, 2, 2, 4, 2, 6, 4, 6, 4]
addresses["Betty Cooper"] = "111 Queens Ave."
addresses["Betty Cooper", default: "Address unknown"]
// => "111 Queens Ave."
constants["Gelfond's"] = 23.140692
// compiler error: "Cannot assign through subscript: 'constants' is a 'let' constant"
Like arrays, the key: value pairs of a dictionary can be stepped through one at a time using a for-in loop. This type of loop takes each key: value pair of the dictionary and binds the pair to a specified name for further processing inside the loop body. The pair is represented as a tuple and can be decomposed like other tuples to assign each element to a name. For example, to print out the address book, on can write:
for (name, address) in addresses {
print("\(name) lives at \(address)")
}
// prints out:
// Betty Cooper lives at 111 Queens Ave.
// The Munsters lives at 1313 Mockingbird Lane
// The Simpsons lives at 742 Evergreen Terrace
// Buffy Summers lives at 1630 Revello Drive
Like the other collection types, dictionaries can be sorted according to arbitrary sorting functions. To do so, one must first define a function that takes two key: value pairs, represented as tuples and returns a Bool
such that the return value is true
if the first key: value pair should appear in the sorted result before the second key: value pair.
This function can then be passed into the dictionary's sorted(by:)
method which will return a sorted array of key: value pairs. E.g. to sort the constants
dictionary by the value of the constant plus the number of characters in the constant's name we could write:
func weirdSort(_ lhs: (String, Double), _ rhs: (String, Double)) -> Bool {
let left = lhs.1 + Double(lhs.0.count)
let right = rhs.1 + Double(rhs.0.count)
return left < right
}
let sortedConstants = constants.sorted(by: weirdSort)
// => [(key "e", value 2.71828), (key "phi", value 1.618033), (key "pi", value 3.14159), (key "avogadro", value 6.02214076e+22)]
In this exercise, you're implementing a way to keep track of the high scores for the most popular game in your local arcade hall.
You have 7 functions to implement, all related to returning and manipulating a dictionary of high score data.
Create a function newScoreBoard()
that takes no parameters and returns a new high score dictionary which uses values of type String
for the keys and values of type Int
as the values.
To add a player to the high score dictionary, define addPlayer
, which is a function which takes 3 parameters:
addPlayer(&highScores, "Dave Thomas")
// Adds "Dave Thomas" to the dictionary with a high score of 0.
addPlayer(&highScores, "José Valim", 486_373)
// Adds "José Valim" to the dictionary with a high score of 486_373.
To remove a player from the high score dictionary, define removePlayer
, which takes 2 parameters:
This function should remove the player from the dictionary if they are in it and do nothing otherwise.
removePlayer(&highScores, "Dave Thomas")
// Removes "Dave Thomas" from thee dictionary
removePlayer(&highScores, "Rose Fanaras")
// Doesn't alter the dictionary as "Rose Fanaras" is not in the dictionary.
To reset a player's score, define resetPlayer
, which takes 2 parameters:
The function will set the score of the player to 0. If the player is not in the dictionary, then nothing should happen.
resetScore(&highScores, "Dave Thomas")
// High score for "Dave Thomas" set to 0
To update a players score by adding to the previous score, define updateScore
, which takes 3 parameters:
addPlayer(&highScores, "Freyja Ćirić", 12_771_008)
updateScore(&highscores, "Freyja Ćirić", 73)
// Score for "Freyja Ćirić" updated to 12_771_081
Define the function orderByPlayers
, which takes 1 parameter:
The function will return an array of (String, Int)
tuples that are the players and their high scores sorted in ascending order by the player's name.
orderByPlayers(highScores)
// => [("Dave Thomas", 0), ("Freyja Ćirić", 12_771_091), ("José Valim", 486_373)]
To get a list of players ordered by scores in decreasing order, define orderByScores
, which takes 1 parameter:
The function will return an array of (String, Int)
tuples that are the players and their high scores sorted in descending order by the player's score.
orderByScores(highScores)
# => [("Freyja Ćirić", 12_771_091), ("José Valim", 486_373), ("Dave Thomas", 0)]
Sign up to Exercism to learn and master Swift with 35 concepts, 100 exercises, and real human mentoring, all for free.