Словари
Чему вы научитесь:
- находить значение по ключу и отличать отсутствующий ключ от нуля;
- добавлять, менять и удалять пары словаря;
- перебирать словарь по порядку ключей и считать повторы через
default:; - хранить значения без повторов в множестве и сравнивать два множества.

Представьте телефонную книгу. Чтобы позвонить Борису, вы не вспоминаете, на какой строке он записан. Вы находите имя и рядом читаете номер. У каждого имени в книге один номер.
Массив из прошлой темы устроен иначе: сразу выдать элемент он может только по индексу. Если известно одно имя, массив приходится проверять с начала, пока имя не найдётся. Для поиска по имени в Swift есть другая коллекция.
Словарь хранит пары и находит значение по ключу. В телефонной книге ключ — имя, а значение — номер телефона:
var phones = ["Anna": "555-1234", "Boris": "555-9876"]
print(phones.count) // 2
print(phones["Anna"] ?? "none") // 555-1234
print(phones["Gleb"] ?? "none") // noneДавайте разберём программу по строкам:
- Первая строка создаёт словарь из двух пар. Каждая пара записана как
ключ: значение, пары разделены запятыми, а весь список стоит в квадратных скобках. phones.count— число пар в словаре, здесь2.phones["Anna"]находит номер Анны, и программа печатает555-1234.- Ключа
"Gleb"в словаре нет. Поиск ничего не находит, и??подставляет вместо ответа строку"none".
Тип словаря
Swift выводит тип словаря из его пар, как выводит тип переменной из значения. Тип phones записывают как [String: String]: в квадратных скобках тип ключей, двоеточие и тип значений.
Что важно знать о ключах и значениях:
- все ключи одного словаря одного типа, и все значения тоже: в
[String: Int]ключи — строки, а значения — целые числа; - ключи не повторяются: у одного имени в книге один номер;
- значения повторяться могут: два человека вправе оставить один домашний номер;
- пустой словарь записывают как
[:], но тип тогда указывают сами:var ages: [String: Int] = [:].
Поиск даёт опционал
Поиск по ключу может ничего не найти. Поэтому phones["Anna"] возвращает не String, а опционал String? — коробку, в которой лежит номер или ничего нет. Открывают её теми же способами, что и любой опционал: через ?? или if let.
if let number = phones["Boris"] {
print("Boris:", number) // Boris: 555-9876
}Блок внутри if выполняется, только если ключ "Boris" нашёлся. Внутри блока number — обычная строка, без вопросительного знака.
На собеседовании часто спрашивают, что будет при поиске по ключу, которого нет в словаре. Ответ: поиск по отсутствующему ключу даёт nil, а индекс за концом массива завершает программу аварийно.
Отсутствующий ключ — не то же самое, что ноль. Если в словаре [String: Int] есть пара "Vera": 0, поиск по "Vera" даёт коробку с 0, и ?? вернёт этот 0, а не запасное значение. nil получается, только когда ключа в словаре нет.
Добавить, изменить, удалить
Словарь в var меняют той же записью в квадратных скобках. Словарь в let менять нельзя: будь phones константой, компилятор ответил бы cannot assign through subscript: 'phones' is a 'let' constant.
Что сделает присваивание, зависит от ключа и от значения справа:
phones["Vera"] = "555-0000"
phones["Anna"] = "555-1111"
phones["Boris"] = nil
print(phones.count) // 2
print(phones["Anna"] ?? "none") // 555-1111
print(phones["Boris"] ?? "none") // noneДобавить пару
Ключа "Vera" в словаре не было, поэтому phones["Vera"] = "555-0000" добавляет новую пару.
Изменить значение
Ключ "Anna" уже есть, поэтому phones["Anna"] = "555-1111" заменяет старый номер новым. Второй пары с ключом "Anna" не появится.
Удалить пару
phones["Boris"] = nil удаляет пару целиком, и поиск по "Boris" теперь даёт nil. Поэтому print(phones.count) печатает 2: пару Веры добавили, а пару Бориса удалили.
Пары без порядка
Здесь картинка с телефонной книгой неточна. В бумажной книге имена идут по алфавиту, а словарь Swift порядка пар не хранит. В каком порядке он перечислит пары, заранее неизвестно.
Частая ошибка
Значение из словаря склеили со строкой, не открыв коробку:
let label = "Anna: " + phones["Anna"] // ✗error: value of optional type 'String?' must be unwrapped to a value of type 'String'Программа не компилируется: поиск даёт String?, а склеить строку можно только со String. Сначала откройте коробку: "Anna: " + (phones["Anna"] ?? "none") даёт Anna: 555-1111.
Главное
- Словарь хранит пары «ключ — значение» и находит значение по ключу; в типе
[String: Int]сначала идёт тип ключей, потом тип значений. - Поиск по ключу даёт опционал: отсутствующий ключ — это
nil, а не аварийное завершение и не ноль. d[key] = valueдобавляет пару или меняет значение, аd[key] = nilудаляет пару.- Ключи в словаре не повторяются, а порядка пар словарь не хранит.