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

Перебор словаря

Вернёмся к телефонной книге. Иногда нужен не один номер, а вся книга сразу: например, чтобы напечатать все контакты. Бумажную книгу вы листали бы страницу за страницей и читали строку за строкой. Словарь тоже можно пройти целиком, но с одной оговоркой о порядке.

Перебор пар

Цикл for-in проходит словарь пара за парой. Каждая пара — кортеж из ключа и значения, и в заголовке цикла его сразу раскладывают на два имени:

SWIFT
let phones = ["Anna": "555-1234", "Boris": "555-9876", "Vera": "555-0000"]
for (name, phone) in phones {
    print(name, phone)
}

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

  1. Первая строка создаёт словарь из трёх пар: ключ — имя, значение — номер.
  2. for (name, phone) in phones на каждой итерации берёт одну пару: ключ попадает в name, значение — в phone.
  3. print(name, phone) печатает имя и номер через пробел.

Программа печатает три строки, по одной на пару. В каком порядке — заранее неизвестно. Запустите её два-три раза, и строки могут выйти в другом порядке: при одном запуске первой идёт Анна, при следующем — Борис.

Это та неточность картинки, о которой шла речь в прошлом уроке: в бумажной книге имена идут по алфавиту. Словарь раскладывает пары так, чтобы быстро находить ключ, а Swift выбирает раскладку заново при каждом запуске программы. Поэтому программа никогда не должна полагаться на порядок пар в словаре.

Если имя или номер в цикле не нужны, вместо них пишут _: for (_, phone) in phones.

Ключи по алфавиту

Когда порядок нужен, его задают сами. phones.keys — все ключи словаря, а sorted() возвращает их массивом по возрастанию. Строки при этом идут по алфавиту, только заглавные латинские буквы стоят раньше строчных:

SWIFT
for name in phones.keys.sorted() {
    print(name, terminator: " ") // Anna Boris Vera
}

Теперь имена идут по алфавиту при каждом запуске: цикл проходит по отсортированному массиву, а не по самому словарю. Номер для каждого имени достают поиском: phones[name] ?? "none". phones.values даёт все значения словаря без ключей, тоже без порядка.

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

Номер достали поиском, но не открыли коробку:

SWIFT
for name in phones.keys.sorted() {
    print(name, phones[name]) // ✗
}
TEXT
warning: expression implicitly coerced from 'String?' to 'Any'

Это предупреждение, поэтому программа запустится. Но вместо Anna 555-1234 цикл напечатает Anna Optional("555-1234"), и так в каждой строке. Имя взято из ключей того же словаря, но компилятор этого не учитывает: поиск по ключу всегда даёт опционал. Откройте коробку: phones[name] ?? "none".

Главное

  • for (key, value) in dict перебирает пары, но их порядок не фиксирован и может меняться от запуска к запуску.
  • Нужен порядок — перебирайте dict.keys.sorted() и доставайте значение поиском по ключу.
  • Поиск даёт опционал, даже когда ключ взят из того же словаря: откройте его через ??.