Как в Swift перебрать массив с получением индекса и элемента одновременно?
Использование метода enumerated() — правильный и безопасный способ
В Swift для перебора массива с одновременным получением индекса и элемента существует встроенный метод enumerated(). Он возвращает последовательность кортежей (tuple), где каждый кортеж состоит из индекса (начиная с 0) и соответствующего элемента массива.
Вот как решить вашу задачу:
let names = ["Анна", "Борис", "Виктор", "Галина"]
for (index, name) in names.enumerated() {
print("\(index + 1). \(name)")
}
Этот код выведет:
1. Анна
2. Борис
3. Виктор
4. Галина
Как это работает
names.enumerated()создаёт ленивую последовательность, которая на каждой итерации выдаёт кортеж(Int, Element).- Мы используем связывание кортежа (tuple pattern binding) —
for (index, name) in ..., чтобы сразу получить индекс и элемент. - Индекс начинается с 0. Если вам нужен отсчёт с 1, просто прибавьте 1:
index + 1.
Почему это лучше, чем for i in 0..<count
- Безопасность: Вы не рискуете выйти за границы массива.
enumerated()гарантированно перебирает ровно столько элементов, сколько есть в массиве. - Читаемость: Код становится самодокументируемым — сразу видно, что вы работаете и с индексом, и с элементом.
- Производительность:
enumerated()не создаёт копию массива. Это ленивая операция — элементы извлекаются по мере необходимости. - Универсальность: Работает с любыми коллекциями, а не только с массивами:
Set,Dictionary,String(как коллекция символов) и т.д.
Более сложный пример с фильтрацией
Предположим, вам нужно получить индексы только чётных чисел из массива:
let numbers = [10, 15, 20, 25, 30, 35]
let evenIndexes = numbers.enumerated().compactMap { (index, value) -> Int? in
return value.isMultiple(of: 2) ? index : nil
}
print(evenIndexes) // [0, 2, 4]
Важный нюанс: изменение массива во время итерации
Если вы попытаетесь изменить массив (добавить или удалить элементы) внутри цикла for (index, name) in names.enumerated(), компилятор выдаст ошибку. Это защита от неопределённого поведения. Если вам нужно модифицировать коллекцию во время итерации, используйте for index in names.indices.reversed() или работайте с копией.
Альтернатива: метод indices
Если вам нужны именно индексы, а не элементы, можно использовать indices:
for index in names.indices {
print("\(index): \(names[index])")
}
Но это менее удобно, чем enumerated(), так как требует повторного обращения к массиву.
В итоге: всегда используйте enumerated(), когда вам нужен индекс вместе с элементом. Это идиоматичный, безопасный и производительный способ в Swift.
Использование zip и indices для нестандартных случаев
Если по какой-то причине метод enumerated() вам не подходит (например, вам нужен нестандартный шаг индексации или работа с двумя массивами одновременно), можно использовать комбинацию zip и indices.
Пример с тем же массивом имён:
let names = ["Анна", "Борис", "Виктор", "Галина"]
for (index, name) in zip(names.indices, names) {
print("\(index + 1). \(name)")
}
Это даст тот же результат. zip создаёт последовательность пар из двух последовательностей. Здесь мы берём индексы массива (names.indices) и сами элементы (names).
Когда это может быть полезно
- Нестандартный шаг: Если вам нужны только чётные индексы, вы можете отфильтровать
names.indicesпередzip. - Два массива:
zipотлично подходит для параллельного перебора двух коллекций:for (name, age) in zip(names, ages). - Контроль над индексами: Вы можете использовать
names.indices.dropFirst(), чтобы пропустить первый элемент, и т.д.
Однако для большинства повседневных задач enumerated() остаётся предпочтительным вариантом из-за своей простоты и читаемости. zip стоит применять только тогда, когда enumerated() не хватает гибкости.
Ответов пока нет.
Войдите чтобы оставить ответ
Блоги