Основы Swift / 6.1. Цикл for-in


Видео


Цикл for-in
Вы можете использовать циклы for-in для итерирования через последовательность, например, элементов массива, интервалы чисел или символов в строке.

Пример демонстрирует использование цикла for-in для итерирования через элементы массива:
@{6.1\1}
                    
let names = ["Лёша", "Альфия", "Саша", "Валерия"]
for name in names {
    print("Здравствуй, \(name)!")
}
                    
                
Цикл for-in для словарей
Вы можете так же проитерироваться через словарь с доступом к его парам ключ-значение. Каждый элемент в словаре возвращается в качестве кортежа (key, value), и Вы можете декомпозировать члены кортежа (key, value) в явно именованные константы для использования в теле цикла.

В коде примера ключи словаря декомпозированы в константу с именем animalName, а значения словаря декомпозируются в константу с именем legCount,
@{6.1\2}
                    
let numberOfLegs = ["паук": 8, "муравей": 6, "кот": 4]
for (animalName, legCount) in numberOfLegs {
    print("\(animalName) имеет \(legCount) ног(и)")
}
                    
                
Содержимое Dictionary неупорядочено, а итерирование через него не гарантирует порядок получения элементов. В частности, порядок, в котором Вы вставляете элементы в Dictionary, не определяет порядок, в котором они обходятся.
Цикл for-in для числовых интервалов
Вы так же можете использовать циклы for-in с числовыми интервалами.

Оператор закрытого интервала (a…b) определяет интервал от a до b включая границы. Значение a не должно быть больше b.

Оператор закрытого интервала применим при прохождении через интервал, в котором Вы хотите использовать все значения.

Этот пример печатает первые несколько строк в таблице умножения на 5:
@{6.1\3}
                    
for index in 1...5 {
    print("\(index) умножить на 5 равно \(index * 5)")
}
                    
                
Последовательность в примере - есть интервал значений от 1 до 5 включительно. Значение index устанавливается в первое число в диапазоне (1), и инструкции внутри цикла начинают своё выполнение. В этом случае тело содержит лишь одну инструкцию, которая печатает строчки для таблицы умножения для текущего значения index. После выполнения инструкции значение index будет обновлено и будет содержать второе значение из интервала (2), а функция print(_:separator:terminator:) будет снова вызвана. Этот процесс будет продолжаться до тех пор, пока не будет достигнут конец интервала.

В примере выше index - это константа, значение которой автоматически устанавливается в начале каждой итерации цикла. index неявно объявляется простым включением в декларацию цикла без необходимости объявления с помощью ключевого слова let.
Игнорирование значения
Если Вам не нужно каждое значение из последовательности, то Вы можете проигнорировать значения, использовав символ нижнего подчёркивания вместо имени переменной.
@{6.1\4}
                    
let base = 3
let power = 10
var answer = 1
for _ in 1...power {
    answer *= base
}
print("\(base) в степени \(power) равно \(answer)")
                    
                
В примере вычисляется значение одного числа в степени другого (в этом случае, 3 в степени 10). Происходит умножение начального значения 1 (что является 3 в степени 0) на 3 десять раз с использованием закрытого интервала от 1 до 10. В данном случае нет необходимости знать значения счётчика во время каждой итерации цикла - он просто должен выполниться корректное число раз. Символ нижнего подчёркивания (_) игнорирует её отдельные значения и не предоставляет доступ к текущему значению во время каждой итерации цикла.
Полуинтервалы
В некоторых ситуациях Вам может не быть надобности использовать закрытые интервалы, которые включают обе граничные точки. Например, отрисовка минут на таймере. Используйте полуоткрытый интервал (..<) для включения нижней границы, но не исключения верхней.

Оператор полуоткрытого интервала (a..< b) определяет интервал от a до b, содержащий a, но не включающий b. Он называется полуоткрытым, так как содержит первое значение, но не последнее. Так же, как и в операторе закрытого интервала, a не должно быть больше b. Если значение a будет совпадать с b, то результирующий интервал будет пустым.

Полуоткрытые интервалы крайне полезны, когда Вы работаете с коллекциями с отсчётом индексов с нуля, где бывает полезным считать до (невключительно) длины коллекции:
@{6.1\5}
                    
let names = ["Лёша", "Альфия", "Саша", "Валерия"]
for index in 0..< names.count {
    print("Здравствуй, человек №\(index+1), \(names[index])!")
}
                    
                
Заметьте, что массив содержит четыре элемента, но 0..< count посчитает только до 3 (индекс последнего элемента массива), так как это полуоткрытый интервал.
Односторонние интервалы
Оператор закрытого интервала имеет альтернативную форму записи для интервалов, которые продолжаются в одном направлении до тех пор, пока это возможно, например, для интервала, который содержит все элементы массива, начиная с индекса 2 и до конца массива. В этой ситуации Вы можете опустить значение одной стороны оператора интервала. Этот тип интервала называется односторонним интервалом, так как оператор имеет границу только на одной стороне. Например:
@{6.1\6}
                    
let names = ["Лёша", "Альфия", "Саша", "Валерия"]
for name in names[2...] {
    print(name)
}
for name in names[...2] {
    print(name)
}
                    
                
Односторонняя форма полуоткрытого интервала
Оператор полуоткрытого интервала также имеет одностороннюю форму, которая записывается лишь с её последним значением. Последнее значение не является частью интервала. Например:
@{6.1\7}
                    
let names = ["Лёша", "Альфия", "Саша", "Валерия"]
for name in names[..<2] {
    print(name)
}
                    
                
Другие применения односторонних интервалов
Односторонние интервалы могут быть использованы и вдругих контекстах, а не только в сабскриптах. Вы не можете итерироваться через односторонний интервал с опущенным первым значением, так как неясно, откуда начинается итерирование. Вы можете итерироваться через односторонний интервал, который не содержит финального значения; однако, так как интервал продолжается бесконечно, то убедитесь, что Вы добавили явное условие выхода из цикла. Вы можете проверить, содержит ли односторонний интервал конкретное значение, как указано в коде.
@{6.1\8}
                    
let range = ...5
range.contains(7)   // false
range.contains(4)   // true
range.contains(-1)  // true
                    
                
Интервалы с шагом
Некоторых людей устроило бы обновление таймера раз в 5 минут. Используйте функцию stride(from:to:by) для пропуска ненужных значений:
@{6.1\9}
                    
let minuteInterval = 5
for tickMark in stride(from: 0, to: minutes, by: minuteInterval) {
    // рендерить знак времени каждые 5 минут (0, 5, 10, 15 ... 45, 50, 55)
}
                    
                
Отрезки
Отрезки также допустимо использовать с помощью stride(from:through:by):
@{6.1\10}
                    
let hours = 12
let hourInterval = 3
for tickMark in stride(from: 3, through: hours, by: hourInterval) {
    // рендерить знак времени каждые 3 часа (3, 6, 9, 12)
}