Перебор массива
Представьте, что вы идёте вдоль ряда шкафчиков и открываете их по очереди, от первого до последнего. В каждом вы что-то делаете: пересчитываете вещи или ищете нужную. Цикл for-in умеет так же проходить по массиву.
Вот программа, которая складывает все оценки:
let scores = [7, 9, 4]
var total = 0
for score in scores {
total += score
}
print(total) // 20Давайте разберём её по шагам:
for score in scoresна каждой итерации кладёт в константу циклаscoreследующий элемент: сначала7, потом9, потом4.- Тело прибавляет элемент к
total. - Элементы кончились, цикл завершился, и
printпечатает20.
Индексы здесь не нужны вовсе. Цикл сам идёт по элементам по порядку и никогда не выходит за границы массива.
Здесь картинка с рядом шкафчиков неточна. Открыв шкафчик, вы можете переложить в нём вещь. А score — константа цикла с копией элемента, и через неё массив не изменить.
Номер и элемент вместе
Иногда нужен и элемент, и его индекс: например, чтобы напечатать место участника рядом с набранными им очками. Для этого есть два способа.
enumerated()
scores.enumerated() даёт на каждой итерации кортеж из двух частей: номер элемента и сам элемент. Запись (i, score) разбирает кортеж на два имени, как let (a, b) = … в теме про функции. Что важно запомнить:
- первым идёт номер, вторым — элемент;
- номера начинаются с
0, как индексы; - если одна часть не нужна, вместо её имени пишут
_:for (i, _) in scores.enumerated().
indices
scores.indices — все допустимые индексы массива, от 0 до count - 1. Цикл по ним даёт только номера, а элемент читают по индексу: scores[i]. По индексу элемент можно и заменить: если массив объявлен через var, scores[i] *= 2 в таком цикле удвоит каждый элемент.
for (i, score) in scores.enumerated() {
print(i, score, terminator: "; ") // 0 7; 1 9; 2 4;
}
print()
for i in scores.indices {
print(i, terminator: " ") // 0 1 2
}
print()Этот вопрос часто задают на собеседовании: с какого числа enumerated() начинает счёт и в каком порядке идут части кортежа. Ответ: с нуля, сначала номер, потом элемент.
Порядок
sorted()
scores.sorted() возвращает новый массив, в котором элементы стоят по возрастанию. Сам scores остаётся прежним.
reversed()
scores.reversed() даёт элементы в обратном порядке, но не новый массив: print(scores.reversed()) не напечатает [4, 9, 7]. Поэтому по таким элементам проходят циклом for-in. Сам массив и здесь не меняется.
print(scores.sorted(), scores) // [4, 7, 9] [7, 9, 4]
for score in scores.reversed() {
print(score, terminator: " ") // 4 9 7
}
print()Частая ошибка
Ждали, что sorted() отсортирует сам массив:
var marks = [3, 1, 2]
marks.sorted() // ✗
print(marks) // [3, 1, 2]warning: result of call to 'sorted()' is unusedПрограмма запускается, но печатает [3, 1, 2]. sorted() построил новый отсортированный массив, и его никто не сохранил. Компилятор об этом и предупреждает: результат вызова не используется. У remove(at:) такого предупреждения нет: он сам меняет массив, и удалённый элемент можно не забирать.
Исправить можно двумя способами:
- сохранить результат:
let sortedMarks = marks.sorted(); - если
marksобъявлен черезvar, отсортировать сам массив методомsort(): послеmarks.sort()вmarksлежит[1, 2, 3].
Главное
for x in arrayпроходит элементы по порядку и не выходит за границы массива.enumerated()даёт кортеж «номер, элемент» с номерами от0, аindices— все допустимые индексы.sorted()возвращает новый массив, аsort()сортирует сам массив, объявленный черезvar;reversed()массив не меняет.