Генераторы списков (List comprehension) в Python

Работа с генераторами списков Python на примерах: вложенные списки, простые и вложенные генераторы

Генератор списков — специальная конструкция, с помощью которой можно по определенным правилам создавать заполненные списки, а также редактировать их.

Главное достоинство генераторов в их короткой записи, обычно это одна строка в квадратных скобках.

Синтаксис генератора списков

[выражение for переменная in источник if условие]

выражение — результат этого выражения и будет элемент будущего списка
переменная — переменная для итерации источника
источник — итерируемый объект
условие — выражение, использующее переменную для сравнения на каждой итерации

Условие — не обязательная часть конструкции и может быть пропущена (это будет означать if True).
Если условие получает результат False, то выражение пропускается, и элемент этой итерации в список не добавляется.

пример работы генератора списков

Примеры генератора списков

a = [i for i in range(1, 5)]
print(a)
#[1, 2, 3, 4]

Мы создали список из диапазона от 1 до 5 не включительно.

Если это делать без помощи генератора, то это могло бы выглядеть так:

a = []
for i in range(1, 5):
    a.append(i)
print(a)
#[1, 2, 3, 4]

Создание списка с помощью генератора выглядит короче и лаконичнее.

Генератор списков с условием

a = [i for i in range(1, 5) if i % 2 == 0]
print(a)
#[2, 4]

Здесь мы создали список из того же диапазона, но в список добавили только четные числа, использовав условие «если остаток от деления на 2 равен 0».

Создадим список на основе другого списка, поместим во второй список квадраты значений первого списка:

a = [1, 2, 3, 4]
b = [i ** 2 for i in a]
print(b)
#[1, 4, 9, 16]

Здесь мы берем каждый элемент первого списка с помощью цикла for, возводим во вторую степень и записываем полученное значение в новый список b.

Работа генератора списков со словарем

a = {1:10, 2:20, 3:30}
b = [i * a[i] for i in a]
print(b)
#[10, 40, 90]

Итоговый список получился из произведений ключа словаря на его значение.

Работа генератора со строкой

a = 'python'
b = [i for i in a]
print(b)
#['p', 'y', 't', 'h', 'o', 'n']

Таким образом, мы получили из строки список, состоящий из букв строки.

Генерация вложенных списков

Если один генератор вложить в другой, то в итоге можно получить вложенные списки:

n = 3
a = [[0 for i in range(n)] for i in range(n)]
print(a)
#[[0, 0, 0], [0, 0, 0], [0, 0, 0]]

С помощью переменной n мы задали, сколько вложенных списков и значений во вложенных списках нужно получить.
Далее переменной a мы присваиваем список созданный генератором в квадратных скобках.
Первая часть [0 for i in range(n)] — генерирует значения вложенных списков, в данном случае три нуля в каждом списке
Вторая часть for i in range(n) — генерирует количество этих списков, в данном случае три вложенных списка.

Если все значения вложенных списков должны быть одинаковыми, то можно записать еще проще:

n = 3
a = [[0] * n for i in range(n)]
print(a)
#[[0, 0, 0], [0, 0, 0], [0, 0, 0]]

Еще один пример:

a = [[i, i+1, i+2] for i in range(3)]
print(a)
#[[0, 1, 2], [1, 2, 3], [2, 3, 4]]

Дополнительный способ создания вложенных списков с помощью генератора, когда циклы идут друг за другом:

a = [[a, b] for a in range(3) for b in range(3)]
print(a)
#[[0, 0], [0, 1], [0, 2], [1, 0], [1, 1], [1, 2], [2, 0], [2, 1], [2, 2]]

Для наглядности этот генератор можно записать так:

a = [[a, b] 
     for a in range(3) 
     for b in range(3)
     ]
print(a)
#[[0, 0], [0, 1], [0, 2], [1, 0], [1, 1], [1, 2], [2, 0], [2, 1], [2, 2]]

Здесь имеются вложенные циклы for, которые идут один за другим. Второй цикл for b вложен в первый цикл for a.
Т.е. в одной итерации цикла for a мы получаем 3 итерации цикла for b.
Таким образом, формируется список из 9 вложенных списков.

Решение распространенных задач с помощью генераторов списков

Вводим числа через пробел, на выходе получаем список с элементами int():

a = input().split()
a = [int(i) for i in a]
print(a)
#1 2 3 4 5
#[1, 2, 3, 4, 5]

Разбить целое число на цифры и получить их в виде списка:

num = 95874
x = [int(a) for a in str(num)]
print(x)
#[9, 5, 8, 7, 4]

Сумма пар значений двух списков:

lst_in1 = [1, 2, 3, 4, 5]
lst_in2 = [1, 2, 3, 4, 5]
lst = [lst_in1[i] + lst_in2[i] for i in range(len(lst_in1))]
print(lst)
#[2, 4, 6, 8, 10]

Преобразовать двумерный список в одномерный:

matrix = [[1, 2, 3],
          [4, 5, 6],
          [7, 8, 9]]
new_list = [x
            for row in matrix
            for x in row
            ]
print(new_list)
#[1, 2, 3, 4, 5, 6, 7, 8, 9]

Транспонирование матрицы:

1 2  3  4     1 5 9
5 6  7  8     2 6 10
9 10 11 12    3 7 11
              4 8 12
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]]

Cгенерировать вложенный список размером N x N

Где первая строка содержала бы все нули, вторая — все единицы, третья — все двойки и так до N-й строки.

n = int(input())
for i in range(n):
    lst = [i for x in range(n)]
    print(*lst)
#4
#0 0 0 0
#1 1 1 1
#2 2 2 2
#3 3 3 3

Содержание: