Dictionary
A collection whose elements are key-value pairs.
@frozen struct Dictionary<Key, Value> where Key : Hashable
Overview
A dictionary is a type of hash table, providing fast access to the entries it contains. Each entry in the table is identified using its key, which is a hashable type such as a string or number. You use that key to retrieve the corresponding value, which can be any object. In other languages, similar data types are known as hashes or associated arrays.
Create a new dictionary by using a dictionary literal. A dictionary literal is a comma-separated list of key-value pairs, in which a colon separates each key from its associated value, surrounded by square brackets. You can assign a dictionary literal to a variable or constant or pass it to a function that expects a dictionary.
Here’s how you would create a dictionary of HTTP response codes and their related messages:
var responseMessages = [200: "OK",
403: "Access forbidden",
404: "File not found",
500: "Internal server error"]
The responseMessages
variable is inferred to have type [Int: String]
. The Key
type of the dictionary is Int
, and the Value
type of the dictionary is String
.
To create a dictionary with no key-value pairs, use an empty dictionary literal ([:]
).
var emptyDict: [String: String] = [:]
Any type that conforms to the Hashable
protocol can be used as a dictionary’s Key
type, including all of Swift’s basic types. You can use your own custom types as dictionary keys by making them conform to the Hashable
protocol.
Getting and Setting Dictionary Values
The most common way to access values in a dictionary is to use a key as a subscript. Subscripting with a key takes the following form:
print(responseMessages[200])
// Prints "Optional("OK")"
Subscripting a dictionary with a key returns an optional value, because a dictionary might not hold a value for the key that you use in the subscript.
The next example uses key-based subscripting of the responseMessages
dictionary with two keys that exist in the dictionary and one that does not.
let httpResponseCodes = [200, 403, 301]
for code in httpResponseCodes {
if let message = responseMessages[code] {
print("Response \(code): \(message)")
} else {
print("Unknown response \(code)")
}
}
// Prints "Response 200: OK"
// Prints "Response 403: Access forbidden"
// Prints "Unknown response 301"
You can also update, modify, or remove keys and values from a dictionary using the key-based subscript. To add a new key-value pair, assign a value to a key that isn’t yet a part of the dictionary.
responseMessages[301] = "Moved permanently"
print(responseMessages[301])
// Prints "Optional("Moved permanently")"
Update an existing value by assigning a new value to a key that already exists in the dictionary. If you assign nil
to an existing key, the key and its associated value are removed. The following example updates the value for the 404
code to be simply “Not found” and removes the key-value pair for the 500
code entirely.
responseMessages[404] = "Not found"
responseMessages[500] = nil
print(responseMessages)
// Prints "[301: "Moved permanently", 200: "OK", 403: "Access forbidden", 404: "Not found"]"
In a mutable Dictionary
instance, you can modify in place a value that you’ve accessed through a keyed subscript. The code sample below declares a dictionary called interestingNumbers
with string keys and values that are integer arrays, then sorts each array in-place in descending order.
var interestingNumbers = ["primes": [2, 3, 5, 7, 11, 13, 17],
"triangular": [1, 3, 6, 10, 15, 21, 28],
"hexagonal": [1, 6, 15, 28, 45, 66, 91]]
for key in interestingNumbers.keys {
interestingNumbers[key]?.sort(by: >)
}
print(interestingNumbers["primes"]!)
// Prints "[17, 13, 11, 7, 5, 3, 2]"
Iterating Over the Contents of a Dictionary
Every dictionary is an unordered collection of key-value pairs. You can iterate over a dictionary using a for
-in
loop, decomposing each key-value pair into the elements of a tuple.
let imagePaths = ["star": "/glyphs/star.png",
"portrait": "/images/content/portrait.jpg",
"spacer": "/images/shared/spacer.gif"]
for (name, path) in imagePaths {
print("The path to '\(name)' is '\(path)'.")
}
// Prints "The path to 'star' is '/glyphs/star.png'."
// Prints "The path to 'portrait' is '/images/content/portrait.jpg'."
// Prints "The path to 'spacer' is '/images/shared/spacer.gif'."
The order of key-value pairs in a dictionary is stable between mutations but is otherwise unpredictable. If you need an ordered collection of key-value pairs and don’t need the fast key lookup that Dictionary
provides, see the KeyValuePairs
type for an alternative.
You can search a dictionary’s contents for a particular value using the contains(where:)
or firstIndex(where:)
methods supplied by default implementation. The following example checks to see if imagePaths
contains any paths in the "/glyphs"
directory:
let glyphIndex = imagePaths.firstIndex(where: { $0.value.hasPrefix("/glyphs") })
if let index = glyphIndex {
print("The '\(imagePaths[index].key)' image is a glyph.")
} else {
print("No glyphs found!")
}
// Prints "The 'star' image is a glyph.")
Note that in this example, imagePaths
is subscripted using a dictionary index. Unlike the key-based subscript, the index-based subscript returns the corresponding key-value pair as a non-optional tuple.
print(imagePaths[glyphIndex!])
// Prints "(key: "star", value: "/glyphs/star.png")"
A dictionary’s indices stay valid across additions to the dictionary as long as the dictionary has enough capacity to store the added values without allocating more buffer. When a dictionary outgrows its buffer, existing indices may be invalidated without any notification.
When you know how many new values you’re adding to a dictionary, use the init(minimumCapacity:)
initializer to allocate the correct amount of buffer.
Bridging Between Dictionary and NSDictionary
You can bridge between Dictionary
and NSDictionary
using the as
operator. For bridging to be possible, the Key
and Value
types of a dictionary must be classes, @objc
protocols, or types that bridge to Foundation types.
Bridging from Dictionary
to NSDictionary
always takes O(1) time and space. When the dictionary’s Key
and Value
types are neither classes nor @objc
protocols, any required bridging of elements occurs at the first access of each element. For this reason, the first operation that uses the contents of the dictionary may take O(n).
Bridging from NSDictionary
to Dictionary
first calls the copy(with:)
method (- copyWithZone:
in Objective-C) on the dictionary to get an immutable copy and then performs additional Swift bookkeeping work that takes O(1) time. For instances of NSDictionary
that are already immutable, copy(with:)
usually returns the same dictionary in O(1) time; otherwise, the copying performance is unspecified. The instances of NSDictionary
and Dictionary
share buffer using the same copy-on-write optimization that is used when two instances of Dictionary
share buffer.