Мне нужно иметь возможность составить список, содержащий все возможные комбинации введенного списка. Например, список [1,2,3]
должен возвращать [1 [1,2] [1,3] 2 [2,3] 3 [1,2,3]]
Список не обязательно должен быть ни в одном определенный порядок. На этом сайте я нашел множество функций, используя itertools
но те возвращают объекты, когда мне нужен только list
.
Создание всех возможных комбинаций списка
Ответ 1
Просто используйте itertools.combinations
. Например:
import itertools
lst = [1, 2, 3]
combs = []
for i in xrange(1, len(lst)+1):
combs.append(i)
els = [list(x) for x in itertools.combinations(lst, i)]
combs.append(els)
Теперь combs
содержат это значение:
[1, [[1], [2], [3]], 2, [[1, 2], [1, 3], [2, 3]], 3, [[1, 2, 3]]]
Да, это немного отличается от выведенного вами образца, но в этом выпуске вы не указали все возможные комбинации.
Я перечисляю размер комбинации перед фактическим списком для каждого размера, если вам нужны просто комбинации (без размера, как показано в вашем примере вывода), попробуйте эту другую версию кода:
import itertools
lst = [1, 2, 3]
combs = []
for i in xrange(1, len(lst)+1):
els = [list(x) for x in itertools.combinations(lst, i)]
combs.extend(els)
Теперь combs
содержат это значение:
[[1], [2], [3], [1, 2], [1, 3], [2, 3], [1, 2, 3]]
Ответ 2
Модуль itertools
действительно возвращает генераторы вместо списков, но:
- Генераторы часто более эффективны, чем списки (особенно если вы генерируете большое количество комбинаций)
- Вы всегда можете конвертировать генераторы в списки, используя
list(...)
, когда вам действительно нужно.
Функции chain
и combinations
itertools
работают хорошо, но вам нужно использовать Python 2.6 или выше:
import itertools
def all_combinations(any_list):
return itertools.chain.from_iterable(
itertools.combinations(any_list, i + 1)
for i in xrange(len(any_list)))
Затем вы можете вызвать это как таковое:
# as a generator
all_combinations([1,2,3]) # --> <itertools.chain at 0x10ef7ce10>
# as a list
list(all_combinations([1,2,3])) # --> [(1,), (2,), (3,), (1, 2), (1, 3), (2, 3), (1, 2, 3)]
# as a list of lists
[list(l) for l in all_combinations([1,2,3])] # --> [[1], [2], [3], [1, 2], [1, 3], [2, 3], [1, 2, 3]]
Если вы раньше не использовали генераторы, обратите внимание, что вы их просматриваете, как если бы они были списком, например:
# a generator returned instead of list
my_combinations = all_combinations([1,2,3])
# this would also work if `my_combinations` were a list
for c in my_combinations:
print "Combo", c
"""
Prints:
Combo (1,)
Combo (2,)
Combo (3,)
Combo (1, 2)
Combo (1, 3)
Combo (2, 3)
Combo (1, 2, 3)
"""
Разница в производительности может быть значительно. Если вы сравните производительность, вы увидите, что генератор намного быстрее создает:
# as a generator
all_combinations(range(25)) # timing: 100000 loops, best of 3: 2.53 µs per loop
# as a list
list(all_combinations(range(25))) # timing: 1 loops, best of 3: 9.37 s per loop
Обратите внимание, что все равно потребуется некоторое время для повторения всех комбинаций в любом случае, но это может быть большой победой для вас, особенно если вы найдете то, что ищете раньше.
Ответ 3
Вы можете решить свою проблему, используя itertools.combinations
внутри цикла:
>>> l = [1,2,3]
>>> comb = []
>>> for i in range(len(l)):
... comb += itertools.combinations(l,i+1)
...
>>> comb
[(1,), (2,), (3,), (1, 2), (1, 3), (2, 3), (1, 2, 3)]
И если вы хотите, чтобы они были в списке:
>>> comb_list = [ list(t) for t in comb ]
>>> comb_list
[[1], [2], [3], [1, 2], [1, 3], [2, 3], [1, 2, 3]]
РЕДАКТИРОВАТЬ: Первый параметр комбинаций - это итерируемый, а второй - длина полученных кортежей (в данном случае, от 1
до len(l)
).
Подробнее о комбинациях: http://docs.python.org/library/itertools.html#itertools.combinations
Ответ 4
Функции модуля itertools возвращают итераторы. Все, что вам нужно сделать, чтобы преобразовать их в списки, - это вызов list()
результата.
Однако, поскольку вам нужно будет вызывать itertools.combinations
три отдельных раза (один раз для каждой разной длины), вы можете просто использовать list.extend
, чтобы добавить все элементы итератора в ваш окончательный список.
Попробуйте следующее:
import itertools
in_list = [1, 2, 3]
out_list = []
for i in range(1, len(in_list)+1):
out_list.extend(itertools.combinations(in_list, i))
Или как понимание списка:
out_list = [c for i in range(len(in_list)) for c in itertools.combinations(in_list, i+1)]
Это приведет к следующему списку:
[(1,), (2,), (3,), (1, 2), (1, 3), (2, 3), (1, 2, 3)]
Если вам нужны списки вместо кортежей, а для преобразования однотипных кортежей - только значение, вы можете сделать следующее:
out_list = [x[0] if len(x) == 1 else list(x) for x in out_list]
# [1, 2, 3, [1, 2], [1, 3], [2, 3], [1, 2, 3]]
Или оставить отдельные элементы в виде списков:
out_list = map(list, out_list)
Ответ 5
l = [1,2,3]
combs = reduce(lambda x, y: list(itertools.combinations(l, y)) + x, range(len(l)+1), [])
Если вы хотите использовать oneliner.