Преобразование коллекции
Преобразование берёт коллекцию, например список или словарь, и строит из неё новую коллекцию. Исходная коллекция не изменяется.
В Python основной инструмент для этого — включение (comprehension): короткое выражение в квадратных скобках, которое строит новый список, или в фигурных скобках — для нового словаря. Большинство преобразований на этой странице занимают одну строку. Встроенные функции zip и enumerate и строковый метод join покрывают остальное.
В Python также есть встроенная функция map(), которая применяет функцию к каждому элементу. Она работает, но включение выражает то же самое понятнее и к тому же умеет пропускать элементы, поэтому на этой странице используются включения.
Отображение (map)
Операция map применяет одну и ту же функцию к каждому элементу и собирает ответы в новый список той же длины. Например, она может превратить [1, 2, 3] в [3, 6, 9].
В Python для этого пишут списковое включение: [x * 3 for x in numbers]. Оно читается почти как английская фраза: новый список содержит x * 3 для каждого x в numbers.
Не путайте это со встроенной функцией Python map(), которая делает ту же работу, но принимает объект функции. Здесь «map» означает «применить выражение к каждому элементу».
Map со списковым включением
Включение вычисляет выражение для каждого элемента и собирает результаты в новый список. Здесь оно умножает каждое число на 3.
Вывод: полная программа на Python
numbers = [1, 2, 3]
# включение применяет выражение к каждому элементу
tripled = [x * 3 for x in numbers]
print(tripled)
Map с индексом
Иногда важна и позиция элемента. enumerate даёт и индекс, и значение, поэтому включение может использовать оба. Здесь каждое значение умножается на свой индекс.
Вывод: полная программа на Python
numbers = [1, 2, 3]
# enumerate даёт индекс и значение каждого элемента
result = [value * idx for idx, value in enumerate(numbers)]
print(result)
Пропуск некоторых результатов
Иногда некоторые результаты нужно отбросить. В Python функция может вернуть None, чтобы сказать «результата нет». Первое включение сохраняет все ответы, включая None. Второе содержит часть if, которая оставляет только результаты, не равные None.
Вывод: полная программа на Python
def triple_or_none(x):
if x == 2:
return None # для этого элемента результата нет
return x * 3
numbers = [1, 2, 3]
mapped = [triple_or_none(x) for x in numbers]
print(mapped)
# часть if отбрасывает каждый результат None
result = [r for r in mapped if r is not None]
print(result)
Преобразование ключей словаря
Чтобы изменить ключи словаря, постройте новый словарь с помощью словарного включения по items(). Здесь upper() переводит каждый ключ в верхний регистр. Словарь хранит записи в порядке вставки, поэтому вывод всегда идёт в одном и том же порядке.
Вывод: полная программа на Python
numbers_map = {"key1": 1, "key2": 2}
# копируем каждую запись, но переводим ключ в верхний регистр
upper_keys = {key.upper(): value for key, value in numbers_map.items()}
print(upper_keys)
Преобразование значений словаря
Чтобы изменить значения, сделайте то же самое, но оставьте ключ и вычислите новое значение. Здесь каждое значение увеличивается на длину своего ключа: 1 + len("key1") равно 5.
Вывод: полная программа на Python
numbers_map = {"key1": 1, "key2": 2}
# сохраняем ключ, изменяем значение
new_values = {key: value + len(key) for key, value in numbers_map.items()}
print(new_values)
Zip
Zip берёт два списка и объединяет их элементы в пары по позиции: первый с первым, второй со вторым и так далее. В результате получается столько пар, сколько элементов в более коротком списке.
В Python есть встроенная функция zip. Она возвращает ленивый итератор кортежей, поэтому оберните её в list(), если хотите увидеть пары или использовать их повторно.
Zip двух списков
zip объединяет в пару один цвет с одним животным и сама останавливается на более коротком списке. Каждая пара — это кортеж, который выводится в круглых скобках.
Вывод: полная программа на Python
colors = ["red", "brown", "grey"]
animals = ["fox", "bear", "wolf"]
# zip объединяет элементы в пары по позиции и останавливается на более коротком списке
pairs = list(zip(colors, animals))
print(pairs)
Zip с преобразованием
Сами пары нужны не всегда. Здесь включение проходит по zip(colors, animals) и строит предложение из каждой пары. capitalize() делает первую букву названия животного заглавной.
Вывод: полная программа на Python
colors = ["red", "brown", "grey"]
animals = ["fox", "bear", "wolf"]
# сразу используем оба элемента, чтобы построить предложение
sentences = ["Животное " + animal.capitalize() + ", цвет: " + color
for color, animal in zip(colors, animals)]
for line in sentences:
print(line)
Разделение списка пар (unzip)
Unzip — обратная операция: один список пар превращается в две коллекции. Звёздочка в zip(*number_pairs) распаковывает список, поэтому zip получает три пары как отдельные аргументы и перегруппировывает их первые и вторые части. Оба результата — кортежи.
Вывод: полная программа на Python
number_pairs = [("one", 1), ("two", 2), ("three", 3)]
# звёздочка распаковывает список, zip перегруппировывает первые и вторые части
words, numbers = zip(*number_pairs)
print(words)
print(numbers)
Сопоставление (associate)
Сопоставление строит словарь из списка. Каждый элемент даёт один ключ и одно значение. Словарь не может хранить один и тот же ключ дважды, поэтому если два элемента дают одинаковый ключ, побеждает более поздний.
В Python для этого пишут словарное включение: {key: value for element in items}, где ключ и значение вычисляются из каждого элемента.
Элементы как ключи
Сам элемент становится ключом, а значение вычисляется из него. Здесь слова — это ключи, а их длины — значения.
Вывод: полная программа на Python
numbers = ["one", "two", "three"]
# каждое слово становится ключом, его длина — значением
lengths = {word: len(word) for word in numbers}
print(lengths)
Элементы как значения
Элемент становится значением, а ключ вычисляется из него. Здесь ключ — первая буква в верхнем регистре. И two, и three начинаются с T, поэтому three заменяет two, и в словаре остаются только две записи.
Вывод: полная программа на Python
numbers = ["one", "two", "three"]
# ключ — первая буква; более позднее слово заменяет
# более раннее с тем же ключом
by_first_letter = {word[0].upper(): word for word in numbers}
print(by_first_letter)
Вычисление и ключа, и значения
Из элемента можно вычислить и ключ, и значение. Здесь ключ — первая буква, а значение — длина слова. И снова побеждает более поздняя запись с ключом T.
Вывод: полная программа на Python
numbers = ["one", "two", "three"]
# ключ — первая буква, значение — длина слова
length_by_letter = {word[0].upper(): len(word) for word in numbers}
print(length_by_letter)
Ключ и значение из одного элемента
Иногда один элемент содержит обе части. split() разрезает полное имя по пробелам на список слов, а распаковка даёт имена обеим частям. Фамилия становится ключом, а имя — значением.
Вывод: полная программа на Python
names = ["Alice Adams", "Brian Brown"]
by_last_name = {}
for full_name in names:
first, last = full_name.split() # разбиваем по пробелам
by_last_name[last] = first # фамилия -> имя
print(by_last_name)
Выравнивание (flatten)
Выравнивание превращает вложенную коллекцию, например список списков, в один плоский список со всеми элементами по порядку.
Включение может содержать две части for: [n for inner in number_sets for n in inner]. Читайте их слева направо: для каждого внутреннего списка, для каждого элемента в нём, сохранить элемент.
Выравнивание списка списков
Включение проходит по каждому внутреннему списку и собирает все его элементы в result. Два внутренних списка по три числа превращаются в один список из шести.
Вывод: полная программа на Python
number_sets = [[1, 2, 3], [4, 5, 6]]
# для каждого внутреннего списка, для каждого элемента в нём, сохраняем элемент
result = [n for inner in number_sets for n in inner]
print(result)
Выравнивание значений из объектов
Flat map сначала берёт список из каждого элемента, а затем соединяет все эти списки вместе. Здесь первый for проходит по контейнерам, а второй — по c.values. Все значения из трёх контейнеров оказываются в одном списке.
Вывод: полная программа на Python
class Container:
def __init__(self, values):
self.values = values
containers = [
Container(["one", "two", "three"]),
Container(["four", "five"]),
Container(["six", "seven", "eight"]),
]
# берём значения каждого контейнера и добавляем их все в один список
result = [value for c in containers for value in c.values]
print(result)
Строковое представление
Часто нужно показать коллекцию в виде читаемого текста, например с запятыми между элементами.
В Python у строки-разделителя есть метод join: ", ".join(words) возвращает одну строку. join принимает только строки, поэтому числа нужно сначала преобразовать, например с помощью str(n) во включении. Дополнительные возможности — префикс, постфикс, ограничение или преобразование — делаются обычной конкатенацией строк или срезом перед соединением.
Соединение с разделителем
join ставит ", " между словами и возвращает одну строку. Обратите внимание, что разделитель стоит первым: это строка, у которой вызывается метод.
Вывод: полная программа на Python
numbers = ["one", "two", "three"]
print(", ".join(numbers))
Добавление префикса и постфикса
Префикс и постфикс — это просто текст вокруг соединённого результата. В Python их добавляют с помощью +.
Вывод: полная программа на Python
numbers = ["one", "two", "three"]
# добавляем префикс и постфикс вокруг соединённого текста
text = "начало: " + " | ".join(numbers) + ": конец"
print(text)
Ограничение количества элементов
Для длинного списка может понадобиться показать только первые несколько элементов. Срез numbers[:10] берёт первые 10, включение превращает каждый из них в строку с помощью str(n), а "<...>" в конце показывает, что остальные элементы были отрезаны.
Вывод: полная программа на Python
numbers = list(range(1, 101))
# берём только первые 10 чисел в виде строк
limit = 10
parts = [str(n) for n in numbers[:limit]]
if len(numbers) > limit:
parts.append("<...>")
print(", ".join(parts))
Преобразование каждого элемента перед соединением
Чтобы изменить каждый элемент перед соединением, постройте включением новый список строк, а затем вызовите для него join. Здесь каждое слово превращается в "Элемент: " плюс слово в верхнем регистре.
Вывод: полная программа на Python
numbers = ["one", "two", "three"]
# сначала изменяем каждое слово, затем соединяем результаты
parts = ["Элемент: " + word.upper() for word in numbers]
print(", ".join(parts))