Python
Вложенные циклы в Python
Вложенный цикл — это цикл внутри другого цикла. Он нужен, когда данные устроены в два уровня: таблица, список списков, игровое поле, матрица, координаты, пары значений
Главная идея простая: внешний цикл выбирает крупный элемент, внутренний проходит по элементам внутри него
Первый пример со списком списков
rows = [
[1, 2, 3],
[4, 5, 6],
]
for row in rows:
for value in row:
print(value)
Вывод:
1
2
3
4
5
6
Сначала внешний цикл берет строку [1, 2, 3], затем внутренний цикл печатает каждое число внутри этой строки. Потом внешний цикл переходит к [4, 5, 6], и внутренний цикл снова проходит по значениям
Внешний и внутренний цикл
Вложенные циклы легче читать, если дать переменным честные имена
table = [
['Анна', 5, 4],
['Олег', 3, 5],
]
for student in table:
for value in student:
print(value)
student — одна строка таблицы
value — отдельная ячейка внутри этой строки
Если назвать обе переменные item, код станет короче, но читать его будет тяжелее
Таблица умножения
Классический пример вложенных циклов — таблица умножения
for x in range(1, 4):
for y in range(1, 4):
print(f'{x} x {y} = {x * y}')
Вывод:
1 x 1 = 1
1 x 2 = 2
1 x 3 = 3
2 x 1 = 2
2 x 2 = 4
2 x 3 = 6
3 x 1 = 3
3 x 2 = 6
3 x 3 = 9
Внешний цикл отвечает за первое число, внутренний — за второе. На каждой паре Python выполняет тело внутреннего цикла
По этой теме полезно отдельно посмотреть Составьте еженедельное расписание занятий, чтобы расширить контекст и сравнить подходы
По этой теме полезно отдельно посмотреть Аннотации типов для декораторов в Python, чтобы расширить контекст и сравнить подходы
Координаты поля
Вложенные циклы часто встречаются в задачах с игровым полем или таблицей координат
for row in range(3):
for col in range(3):
print(f'строка {row}, колонка {col}')
Так можно пройти по клеткам поля 3 на 3
Если нужно вывести поле, а не каждую координату с новой строки:
for row in range(3):
line = ''
for col in range(3):
line += f'({row},{col}) '
print(line)
Внутренний цикл собирает одну строку, а внешний печатает ее после заполнения
Сумма чисел в таблице
Практический пример: посчитать сумму всех значений в списке списков
orders = [
[1200, 800, 500],
[300, 700],
[1500],
]
total = 0
for day in orders:
for amount in day:
total += amount
print(total)
Здесь внешний цикл идет по дням, внутренний — по заказам внутри дня
Такой код легко изменить: можно считать сумму по каждому дню, максимальный заказ или количество заказов больше определенной суммы
Сравнение всех пар
Иногда нужно сравнить каждый элемент одного списка с каждым элементом другого
names = ['Анна', 'Олег']
skills = ['Python', 'SQL', 'Git']
for name in names:
for skill in skills:
print(f'{name} изучает {skill}')
Это даст все сочетания имени и навыка
Но будьте осторожны: если в первом списке 1000 элементов, а во втором 1000, получится миллион операций
break во вложенном цикле
break прерывает только тот цикл, внутри которого находится
table = [
[1, 2, 3],
[4, 0, 6],
[7, 8, 9],
]
for row in table:
for value in row:
if value == 0:
print('найден ноль')
break
В этом примере break остановит внутренний цикл, но внешний продолжит следующую строку
Если нужно полностью прекратить поиск, часто используют флаг
found = False
for row in table:
for value in row:
if value == 0:
found = True
break
if found:
break
print(found)
Когда вложенный цикл лучше заменить
Вложенный цикл не ошибка, но иногда есть более понятный инструмент
Для списка списков можно использовать sum
rows = [[1, 2], [3, 4]]
total = sum(sum(row) for row in rows)
print(total)
Для поиска общих элементов двух списков часто лучше взять множества
a = ['python', 'sql', 'git']
b = ['html', 'git', 'css']
common = set(a) & set(b)
print(common)
Такой вариант короче и быстрее на больших данных
Частые ошибки
- путать внешний и внутренний цикл
- использовать одинаковые имена переменных
- ставить
print()не на тот уровень отступа - ожидать, что
breakостановит сразу оба цикла - делать вложенный цикл на больших списках без оценки количества операций
- решать через вложенный цикл задачу, где проще использовать словарь или множество
Практика
Сделайте три задачи
- Выведите координаты поля 4 на 4
- Посчитайте сумму всех чисел в списке списков
- Найдите общие элементы двух списков сначала вложенным циклом, а потом через
set
После каждой задачи проверьте, сколько раз выполняется внутренний цикл. Это помогает увидеть цену вложенности
Что читать дальше
Если нужно повторить обычный цикл без вложенности, начните с материала Цикл for в Python
Для остановки циклов и пропуска итераций пригодится разбор Break и continue в Python
Вложенные циклы в Python нужны для данных с двумя уровнями: строка и ячейка, список и элемент, координата row и координата col
Читайте их сверху вниз: внешний цикл выбирает контейнер, внутренний работает с содержимым
Если циклы становятся слишком тяжелыми или плохо читаются, проверьте, не подходит ли вместо них словарь, множество, генератор или отдельная функция