Вложенные циклы
Внутри цикла может быть что угодно — в том числе другой цикл. Так перебирают пары чисел, строят таблицы и рисуют фигуры.
Цикл в цикле
for i in range(1, 4):
for j in range(1, 3):
print(i, j)
Вывод:
1 1
1 2
2 1
2 2
3 1
3 2
Для каждого значения i внутренний цикл проходит все свои значения j. Удобно представлять часы: внешний цикл — часовая стрелка, внутренний — минутная. Минутная делает полный круг, прежде чем часовая сдвинется на одно деление.
Сколько раз выполнится тело внутреннего цикла? 3 * 2 = 6. В общем случае — произведение длин циклов.
Строки из символов
Частая задача — печатать узор строка за строкой. Внешний цикл отвечает за строки, внутренний — за символы в строке:
rows, cols = 3, 5
for i in range(rows):
for j in range(cols):
print("o", end="")
print() # конец строки
ooooo
ooooo
ooooo
Обрати внимание на print() после внутреннего цикла — он переводит строку. Он стоит с отступом внешнего цикла, а не внутреннего.
Символ зависит от позиции
Внутри можно решать, что печатать, по номеру строки i и столбца j. Например, рамка — звёздочки по краям, пробелы внутри:
n = 4
for i in range(n):
for j in range(n):
if i == 0 or i == n - 1 or j == 0 or j == n - 1:
print("*", end="")
else:
print(" ", end="")
print()
****
* *
* *
****
А диагональ — это клетки, где i == j. Попробуй сам нарисовать квадрат с диагональю.
Внутренний цикл зависит от внешнего
Границы внутреннего цикла могут зависеть от переменной внешнего:
for i in range(1, 5):
for j in range(i):
print(i, end="")
print()
1
22
333
4444
Так же перебирают пары без повторов: for i in range(n) и for j in range(i + 1, n) — каждая пара (i, j) с i < j встретится ровно один раз.
n = 4
pairs = 0
for i in range(1, n + 1):
for j in range(i + 1, n + 1):
pairs += 1
print(pairs) # 6 пар из 4 чисел
Перебор с проверкой и флаг
Внешний цикл перебирает кандидатов, внутренний проверяет каждого. Чтобы запомнить результат проверки, используют переменную-флаг:
x = 91
ok = True # пока не нашли ничего плохого
for d in range(2, 10):
if x % d == 0:
ok = False # нашли делитель от 2 до 9
break
print(ok) # False: 91 = 7 * 13
Флаг устанавливается перед внутренним циклом — заново для каждого кандидата. Если поставить его один раз в начале программы, он «запомнит» результат предыдущего кандидата.
break во вложенных циклах
break выходит только из того цикла, где написан. Внешний цикл продолжит работу со следующего значения.
Сколько это стоит
Два вложенных цикла по n дают n * n шагов. При n = 1000 это миллион — нормально. При n = 10^5 — уже десять миллиардов, так не успеть. Смотри на ограничения: они подсказывают, сколько циклов можно вложить.
Итог
- для каждого шага внешнего цикла внутренний проходит все свои шаги;
- внешний цикл — строки, внутренний — символы;
print()после внутреннего переводит строку; - границы внутреннего цикла могут зависеть от внешнего, так перебирают пары без повторов;
- флаг ставь перед внутренним циклом;
- число шагов — произведение длин циклов, следи за ограничениями.