Перейти к содержимому
Теория · Словари и множества · урок 1 из 6

Словари

Чему вы научитесь

Чему вы научитесь:

  • находить значение по ключу и отличать отсутствующий ключ от нуля;
  • добавлять, менять и удалять пары словаря;
  • перебирать словарь по порядку ключей и считать повторы через default:;
  • хранить значения без повторов в множестве и сравнивать два множества.
Открытая телефонная книга: строка Anna под лупой и записка Gleb, указывающая на пустую строку nil

Представьте телефонную книгу. Чтобы позвонить Борису, вы не вспоминаете, на какой строке он записан. Вы находите имя и рядом читаете номер. У каждого имени в книге один номер.

Массив из прошлой темы устроен иначе: сразу выдать элемент он может только по индексу. Если известно одно имя, массив приходится проверять с начала, пока имя не найдётся. Для поиска по имени в Swift есть другая коллекция.

Словарь хранит пары и находит значение по ключу. В телефонной книге ключ — имя, а значение — номер телефона:

SWIFT
var phones = ["Anna": "555-1234", "Boris": "555-9876"]
print(phones.count) // 2
print(phones["Anna"] ?? "none") // 555-1234
print(phones["Gleb"] ?? "none") // none

Давайте разберём программу по строкам:

  1. Первая строка создаёт словарь из двух пар. Каждая пара записана как ключ: значение, пары разделены запятыми, а весь список стоит в квадратных скобках.
  2. phones.count — число пар в словаре, здесь 2.
  3. phones["Anna"] находит номер Анны, и программа печатает 555-1234.
  4. Ключа "Gleb" в словаре нет. Поиск ничего не находит, и ?? подставляет вместо ответа строку "none".

Тип словаря

Swift выводит тип словаря из его пар, как выводит тип переменной из значения. Тип phones записывают как [String: String]: в квадратных скобках тип ключей, двоеточие и тип значений.

Что важно знать о ключах и значениях:

  • все ключи одного словаря одного типа, и все значения тоже: в [String: Int] ключи — строки, а значения — целые числа;
  • ключи не повторяются: у одного имени в книге один номер;
  • значения повторяться могут: два человека вправе оставить один домашний номер;
  • пустой словарь записывают как [:], но тип тогда указывают сами: var ages: [String: Int] = [:].

Поиск даёт опционал

Поиск по ключу может ничего не найти. Поэтому phones["Anna"] возвращает не String, а опционал String? — коробку, в которой лежит номер или ничего нет. Открывают её теми же способами, что и любой опционал: через ?? или if let.

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

Что сделает присваивание, зависит от ключа и от значения справа:

SWIFT
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 порядка пар не хранит. В каком порядке он перечислит пары, заранее неизвестно.

Частая ошибка

Значение из словаря склеили со строкой, не открыв коробку:

SWIFT
let label = "Anna: " + phones["Anna"] // ✗
TEXT
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 удаляет пару.
  • Ключи в словаре не повторяются, а порядка пар словарь не хранит.