Stepik: Вложенные циклы и вложенные генераторы списков
a = [(i, j) for i in range(3) for j in range(4)] print(a) # Вывод: [(0, 0), (0, 1), (0, 2), (0, 3), (1, 0), (1, 1), (1, 2), (1, 3), (2, 0), (2, 1), (2, 2), (2, 3)]
a = [(i, j) for i in range(3) if i % 3 == 0 for j in range(4) if j % 2 == 0] print(a) # Вывод: [(0, 0), (0, 2)]
a = [(i, j) for i in range(3) if i % 3 == 0 for j in range(4) if j % 2 == 0 ] print(a) # Вывод: [(0, 0), (0, 2)]
Используя такой подход легко сформировать таблицу умножения
a = [f'{i} * {j} = {i * j}|' for i in range(2, 11) for j in range(1, 11) ] print(*a) # Вывод: 2 * 1 = 2| 2 * 2 = 4| 2 * 3 = 6| 2 * 4 = 8| и тд таблица умножения
Можно двумерный список превратить в одномерный:
matrix = [[0, 1, 2, 3], [10, 11, 12, 13], [20, 21, 22, 23] ] a = [x for row in matrix for x in row ] print(a) # Вывод: [0, 1, 2, 3, 10, 11, 12, 13, 20, 21, 22, 23]
Во вложенных циклах можно использовать переменные, объявленные в этих циклах ранее
Если принимать то, что синтаксис вложенного генератора списков такой:
[<оператор> for <счетчик> in <итерируемый объект>]
тогда что мешает использовать вместо оператора другой генератор списков
[[генератор списка] for <переменная> in <итерируемый объект>]
M, N = 3, 4 matrix = [[a for a in range(M)] for b in range(N)] print(matrix) # Вывод: [[0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1, 2]]
Результат вполне очевиден. Сначала отрабатывает первый (внешний) генератор списка и переменная b = 0
. Затем, выполнение переходит к вложенному генератору, который выдает список [0, 1, 2]
. Этот список помещается как первый элемент основного списка. Далее, снова отрабатывает первый генератор и b
принимает значение 1
. После этого переходим к вложенному генератору, который возвращает такой же список [0, 1, 2]
. И так пока не закончится работа первого генератора. В итоге, видим список, в который вложены четыре других списка.
Этот подход может пригодится для изменения значений двумерного списка.
Давайте предположим, что у нас есть вот такой список и мы хотим возвести все его значения в квадрат.
A = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] A = [[x ** 2 for x in row] for row in A] print(A) # row - переменная для вложенных списков, а х - для каждого значения в списке # Вывод: [[1, 4, 9], [16, 25, 36], [49, 64, 81]]
Другой пример – это транспонирование матрицы A (то есть, замена строк на столбцы) с использованием вложенных генераторов. Сделать это можно следующим образом:
A = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]] A = [[row[i] for row in A] for i in range(len(A[0]))] print(A) # Вывод: [[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]
Сначала значение i = 0
, а переменная row[i]
пробегает первые значения строк матрицы A
. В результате формируется первая строка транспонированной матрицы. Далее, i
увеличивается на 1
и row[i]
пробегает уже вторые элементы строк матрицы A
. Получаем вторую строку транспонированной матрицы. И так делаем для всех столбцов. На выходе формируется транспонированная матрица.
Так же можно поместить генератор списка в качестве итерируемого объекта
[<оператор> for <счетчик> in [генератор списка]]
g = [u ** 2 for u in [x + 1 for x in range(5)]]
Данная конструкция создает список от 1 до 5 ([x + 1 for x in range(5)]
), а затем возводит каждое значение в квадрат
g = [u ** 2 for u in [x + 1 for x in range(5)]] print(g) # Вывод: [1, 4, 9, 16, 25]