Комбинации элементов из нескольких списков в Python
Быстрый ответ
Если вам нужно сгенерировать все комбинации из списка списков в Python, рекомендуется использовать itertools.product
. Этот метод формирует декартово произведение, в результате которого на выходе мы получаем кортежи с элементами из каждого списка.
Вот пример кода для генерации кортежей:
from itertools import product
lists = [[1, 2], [3, 4], [5, 6]]
print(list(product(*lists))) # распаковка списков для передачи в itertools.product
Вы получите следующие кортежи:
[(1, 3, 5), ..., (2, 4, 6)]
Просто замените lists
на собственные данные, запустите скрипт, и наслаждайтесь результатом!
Управление крайними случаями и эффективность использования itertools
А как быть с такими ситуациями, как пустые списки? itertools.product
прекрасно справляется и с ними, эффективно обеспечивая обработку без лишнего проблемного дебага.
При работе с большим объемом данных критична производительность. Благодаря реализации на языке C в Python sklearn, itertools.product
значительно повышает скорость исполнения кода.
Использование рекурсии при отсутствии itertools
Если в вашем распоряжении нет itertools
, вы можете использовать рекурсию для реализации своего собственного генератора комбинаций:
def combine(list_of_lists, prefix=[]):
if not list_of_lists:
yield tuple(prefix)
else:
for item in list_of_lists[0]:
yield from combine(list_of_lists[1:], prefix + [item])
# Пример использования:
for combination in combine([[1,2], [3], [4,5]]):
print(combination)
Такой подход устраняет зависимости от сторонних библиотек и подойдёт даже для старых версий Python, где модуля itertools
еще не предусмотрено.
Вариант с вложенными циклами
Иногда, для формирования сочетаний элементов из списков, вполне достаточно использовать вложенные циклы, без прибегания к itertools или рекурсии:
lists = [[1, 2], [3, 4], [5, 6]]
combinations = []
for a in lists[0]:
for b in lists[1]:
for c in lists[2]:
combinations.append((a, b, c))
print(combinations)
Однако использование вложенных циклов делает код менее универсальным и элегантным по сравнению с itertools.product
.
Решение при помощи Numpy для работы с числовыми данными
Если вы работаете с числами, можно воспользоваться Numpy и его методами numpy.meshgrid
и numpy.reshape
, чтобы получить комбинации в виде массивов:
import numpy as np
lists = [np.array(x) for x in [[1, 2], [3, 4], [5, 6]]]
mesh = np.meshgrid(*lists)
combinations = np.vstack(map(np.ravel, mesh)).T
print(combinations.tolist())
Данное решение отлично подходит для больших числовых расчетов, требующих высокой скорости исполнения, которую обеспечивает NumPy.
Работаем с разнообразием структур данных
У вас нет причин для беспокойства, если вам нужно создать комбинации различных типов данных, таких как строки и числа. itertools.product
и пользовательская рекурсия без особых усилий выполнит эту задачу:
from itertools import product
lists = [['apple', 'banana'], [1, 2, 3], ['x', 'y']]
print(list(product(*lists)))
Достраиваем результат под ваши потребности
Если вам нужен конкретный формат вывода, например, список списков, Вы можете легко его получить, обернув вызов функции product
в генератор списков:
from itertools import product
lists = [[1, 2], [3, 4], [5, 6]]
combinations = [list(combination) for combination in product(*lists)]
print(combinations)
Визуализация
Попробуем посмотреть на это все наглядно. Вообразите шеф-повара 👨🍳 с тремя полками ингредиентов:
Полка 1: [🍅, 🍆] Полка 2: [🧀, 🥚] Полка 3: [🌿, 🌶️]
Для приготовления блюда шеф-повару необходим по одному ингредиенту с каждой полки.
from itertools import product
# Функция `product` в Python, как шеф-повар, выбирает по одному ингредиенту с каждой полки.
Итак, результат:
🍅🧀🌿 | 🍅🧀🌶️ | 🍅🥚🌿 | 🍅🥚🌶️ |
---|---|---|---|
🍆🧀🌿 | 🍆🧀🌶️ | 🍆🥚🌿 | 🍆🥚🌶️ |
Каждая строка таблицы — это готовый набор ингредиентов для блюда! 🍽️
Метод с использованием yield
Рассмотрим еще одну реализацию, которая тоже позволяет получить все возможные комбинации:
def all_combinations(lists):
if len(lists) == 1:
for item in lists[0]:
yield (item,)
else:
for item in lists[0]:
for rest in all_combinations(lists[1:]):
yield (item,) + rest
# Пример использования:
for combination in all_combinations([[1,2], [3,4], [5,6]]):
print(combination)
Работаем с большим количеством данных: переменное количество списков
Важно подчеркнуть, что как itertools.product
, так и рекурсия прекрасно работают не только с двумя, но и с тысячами списков. Главное — корректно использовать распаковку аргументов (*
) с itertools
или обеспечить правильные рекурсивные вызовы и базовые условия.
Такой подход позволит вам справиться с данными любого объема и типа, при этом сохраняя гибкость и элегантность своего решения.
Полезные материалы
- itertools — Функции создания итераторов для эффективного циклического перебора — Python 3.12.2 документация — официальная документация Python по
itertools.product()
. - More Itertools — more-itertools 10.2.0 документация — расширенные инструменты итерации, которые дополняют
itertools
. - Itertools в Python 3, На практике – Real Python — практические примеры использования
itertools
в Python. - Python – Itertools.Product() – GeeksforGeeks — статья, подробно объясняющая использование
itertools.product()
для нахождения декартового произведения. - Функции стандартной библиотеки Python | Programiz — подробное руководство по функции
itertools.product()
.