Вложенные циклы. Примеры задач с вложенными циклами
На предыдущих занятиях мы с вами в деталях познакомились с работой операторов циклов for и while. На этом занятии сделаем следующий важный шаг и узнаем, как реализуются и работают вложенные циклы.
Само это название уже говорит, что один оператор цикла можно вложить в другой. Это могут быть два цикла for или два цикла while или смешанные варианты. Давайте вначале разберемся, как работают эти конструкции. Принцип у всех един, поэтому, для простоты, я возьму два цикла for (один вложен в другой). Эти циклы будут просто пробегать диапазоны чисел, первый от 1 до 3, а второй – от 1 до 5:
for i in range(1, 4): for j in range(1, 6): print(f"i = , j = ", end=' ') print()
Во втором вложенном цикле мы будем выводить значения i и j в строку без перехода на новую строчку. А после завершения работы вложенного цикла вызовем функцию print(), как раз, для перевода курсора на новую строку. В результате выполнения этой программы, мы получим таблицу значений переменных i и j.
Почему получились именно такие значения? Вначале у нас счетчик i принимает значение 1, а счетчик j пробегает числа от 1 до 5, в итоге получаем первую строку. После завершения вложенного цикла, срабатывает функция print() и курсор переходит на новую строку. После этого переходим ко второй итерации первого цикла и i = 2. Счетчик j снова проходит значения от 1 до 5 и получаем вторую строку. На следующей итерации первого цикла i = 3, j проходит от 1 до 5 и получаем третью строку. То есть, у нас вложенный цикл for трижды запускался заново и каждый раз j изменялось от 1 до 5. Это и есть принцип работы вложенного цикла – на каждой итерации он отрабатывает снова и снова, пока не завершится первый цикл.
Теперь второй вопрос – зачем все это нужно? Давайте представим, что у нас есть вложенный (двумерный) список:
a = [[1, 2, 3, 4], [2, 3, 4, 5], [3, 4, 5, 6]]
(О таких списках мы с вами уже говорили и вам здесь все должно быть понятно). Так вот, если мы будем перебирать его элементы с помощью одного оператора цикла for:
for row in a: print(row, type(row))
То переменная row будет ссылаться сначала на первый вложенный список, затем, на второй и потом на третий. Но, так как row ссылается на список, то есть, на итерируемый объект, то нам ничто не мешает перебрать его элементы с помощью второго, вложенного цикла for:
for row in a: for x in row: print(x, type(x), end=' ') print()
Как видите, теперь в консоль выводятся числа типа int, то есть, мы обращаемся непосредственно к элементам этого двумерного списка.
Ну, хорошо, а все-таки, зачем это может быть нужно? Например, так можно выполнить сложение значений из двух одинаковых двумерных списков:
a = [[1, 2, 3, 4], [2, 3, 4, 5], [3, 4, 5, 6]] b = [[1, 1, 1, 1], [2, 2, 2, 2], [3, 3, 3, 3]]
И сформировать на их основе третий список:
for i, row in enumerate(a): r = [] for j, x in enumerate(row): r.append(x + b[i][j]) c.append(r) print(c)
Я здесь воспользовался еще одной уже знакомой нам функцией enumerate(), которая возвращает индекс и значение текущего элемента. Это удобно для реализации данной программы. Внутри первого цикла мы каждый раз создаем новый пустой список и с помощью метода append() добавляем в его конец новый элемент как сумму значений из списков a и b. Полученную строку (список r) мы, затем, добавляем в основной список c. Так вычисляется сумма значений элементов двух одинаковых списков a и b.
Как видите, для реализации данной программы нам потребовался вложенный оператор цикла for. И это лишь один маленький пример. Другой пример, пусть у нас имеется текст, представленный в виде списка:
t = ["– Скажи-ка, дядя, ведь не даром", "Я Python выучил с каналом", "Балакирев что раздавал?", "Ведь были ж заданья боевые,", "Да, говорят, еще какие!", "Недаром помнит вся Россия", "Как мы рубили их тогда!" ]
Здесь в строках присутствуют два и более пробелов. Наша задача удалить их и оставить только один. Сделаем это с помощью вложенных циклов. В первом цикле for будем перебирать строки – элементы списка, а во втором (вложенном) цикле while удалять лишние пробелы:
for i, line in enumerate(t): while line.count(' '): line = line.replace(' ', ' ') t[i] = line print(t)
В качестве условия цикла мы здесь вызываем метод count(), который подсчитывает число фрагментов из двух пробелов подряд. Как только их станет 0 – это будет означать False и цикл завершится. Преобразованная строка становится новым i-м элементом списка и в конце результат выводим в консоль.
Следующий пример. Предположим, вначале мы формируем вложенный список размером M x N элементов. Причем, M, N вводим с клавиатуры. Вначале сформируем список, состоящий из всех нулей:
M, N = list(map(int, input("Введите M и N: ").split())) zeros = [] for i in range(M): zeros.append([0]*N) print(zeros)
А после этого все элементы заменим на единицы, используя вложенные циклы:
for i in range(M): for j in range(N): zeros[i][j] = 1
Как видите, в целом, все достаточно просто.
И последний пример. Пусть у нас имеется квадратный список (размерности совпадают):
A = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]]
Необходимо поменять строки на столбцы и получить новое представление этого же списка. Для этого достаточно поменять местами элементы, стоящие выше главной диагонали с элементами, стоящими ниже главной диагонали. То есть, у нас счетчик i будет меняться от 0 до 3, а счетчик j от i+1 до 3. Затем, соответствующие элементы будем менять между собой:
for i in range(len(A)): for j in range(i+1, len(A)): A[i][j], A[j][i] = A[j][i], A[i][j] for r in A: for x in r: print(x, end='\t') print()
Как видите, у нас получилось нужно преобразование. В математике это называется транспонированием матрицы.
Конечно, уровень вложенности операторов циклов может быть еще больше и два и три и четыре. Однако, на практике слишком большого вложения следует избегать, так как программа становится менее читаемой и гибкой для дальнейшего изменения. Лучше ограничиваться тремя подряд идущими во вложении операторами циклов, не более.
Для закрепления, как всегда, пройдите практические задания и, затем, переходите к следующему уроку.
Видео по теме
#1. Первое знакомство с Python Установка на компьютер
#2. Варианты исполнения команд. Переходим в PyCharm
#3. Переменные, оператор присваивания, функции type и id
#4. Числовые типы, арифметические операции
#5. Математические функции и работа с модулем math
#6. Функции print() и input(). Преобразование строк в числа int() и float()
#7. Логический тип bool. Операторы сравнения и операторы and, or, not
#8. Введение в строки. Базовые операции над строками
#9. Знакомство с индексами и срезами строк
#11. Спецсимволы, экранирование символов, row-строки
#12. Форматирование строк: метод format и F-строки
#13. Списки — операторы и функции работы с ними
#14. Срезы списков и сравнение списков
#15. Основные методы списков
#16. Вложенные списки, многомерные списки
#17. Условный оператор if. Конструкция if-else
#18. Вложенные условия и множественный выбор. Конструкция if-elif-else
#19. Тернарный условный оператор. Вложенное тернарное условие
#21. Операторы циклов break, continue и else
#22. Оператор цикла for. Функция range()
#23. Примеры работы оператора цикла for. Функция enumerate()
#24. Итератор и итерируемые объекты. Функции iter() и next()
#25. Вложенные циклы. Примеры задач с вложенными циклами
#26. Треугольник Паскаля как пример работы вложенных циклов
#27. Генераторы списков (List comprehensions)
#28. Вложенные генераторы списков
#29. Введение в словари (dict). Базовые операции над словарями
#30. Методы словаря, перебор элементов словаря в цикле
#31. Кортежи (tuple) и их методы
#32. Множества (set) и их методы
#33. Операции над множествами, сравнение множеств
#34. Генераторы множеств и генераторы словарей
#35. Функции: первое знакомство, определение def и их вызов
#36. Оператор return в функциях. Функциональное программирование
#37. Алгоритм Евклида для нахождения НОД
#38. Именованные аргументы. Фактические и формальные параметры
#39. Функции с произвольным числом параметров *args и **kwargs
#40. Операторы * и ** для упаковки и распаковки коллекций
#42. Анонимные (lambda) функции
#43. Области видимости переменных. Ключевые слова global и nonlocal
#45. Введение в декораторы функций
#46. Декораторы с параметрами. Сохранение свойств декорируемых функций
#47. Импорт стандартных модулей. Команды import и from
#48. Импорт собственных модулей
#49. Установка сторонних модулей (pip install). Пакетная установка
#50. Пакеты (package) в Python. Вложенные пакеты
#51. Функция open. Чтение данных из файла
#52. Исключение FileNotFoundError и менеджер контекста (with) для файлов
#53. Запись данных в файл в текстовом и бинарном режимах
#55. Функция-генератор. Оператор yield
#56. Функция map. Примеры ее использования
#57. Функция filter для отбора значений итерируемых объектов
#58. Функция zip. Примеры использования
#59. Сортировка с помощью метода sort и функции sorted
#60. Аргумент key для сортировки коллекций по ключу
#61. Функции isinstance и type для проверки типов данных
#62. Функции all и any. Примеры их использования
#63. Расширенное представление чисел. Системы счисления
#64. Битовые операции И, ИЛИ, НЕ, XOR. Сдвиговые операторы
#65. Модуль random стандартной библиотеки
#66. Аннотация базовыми типами
#67. Аннотации типов коллекций
#68. Аннотации типов на уровне классов
#69. Конструкция match/case. Первое знакомство
#70. Конструкция match/case с кортежами и списками
#71. Конструкция match/case со словарями и множествами
#72. Конструкция match/case. Примеры и особенности использования
© 2023 Частичное или полное копирование информации с данного сайта для распространения на других ресурсах, в том числе и бумажных, строго запрещено. Все тексты и изображения являются собственностью сайта