Генерируя все возможные комбинации списка, itertools.combinations пропускает некоторые результаты

Учитывая список элементов в Python, как я могу получить все возможные комбинации элементов?

На этом сайте есть несколько похожих вопросов, которые предлагают использовать itertools.combinations, но возвращают только часть того, что мне нужно:

stuff = [1, 2, 3]
for L in range(0, len(stuff)+1):
    for subset in itertools.combinations(stuff, L):
        print(subset)

()
(1,)
(2,)
(3,)
(1, 2)
(1, 3)
(2, 3)
(1, 2, 3)

Как видите, он возвращает только элементы в строгом порядке, не возвращая (2, 1), (3, 2), (3, 1), (2, 1, 3), (3, 1, 2), (2, 3, 1) и (3, 2, 1). Есть ли обходной путь для этого? Кажется, я ничего не могу придумать.


person Minas Abovyan    schedule 02.07.2013    source источник
comment
порядок в комбинациях не имеет значения, (2, 1) то же, что (1, 2)   -  person Hunter McMillen    schedule 02.07.2013
comment
Хороший вопрос. Хотя технически вы можете написать собственную функцию для получения этих комбинаций.   -  person Sam    schedule 02.07.2013


Ответы (7)


Используйте itertools.permutations:

>>> import itertools
>>> stuff = [1, 2, 3]
>>> for L in range(0, len(stuff)+1):
        for subset in itertools.permutations(stuff, L):
                print(subset)
...         
()
(1,)
(2,)
(3,)
(1, 2)
(1, 3)
(2, 1)
(2, 3)
(3, 1)
....

Справка по itertools.permutations:

permutations(iterable[, r]) --> permutations object

Return successive r-length permutations of elements in the iterable.

permutations(range(3), 2) --> (0,1), (0,2), (1,0), (1,2), (2,0), (2,1)
person Ashwini Chaudhary    schedule 02.07.2013

Вы можете сгенерировать все комбинации списка в Python, используя этот простой код

import itertools

a = [1,2,3,4]
for i in xrange(1,len(a)+1):
   print list(itertools.combinations(a,i))

Результат:

[(1,), (2,), (3,), (4,)]
[(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]
[(1, 2, 3), (1, 2, 4), (1, 3, 4), (2, 3, 4)]
[(1, 2, 3, 4)]
person saimadhu.polamuri    schedule 17.03.2015
comment
Вопрос был задан, чтобы увидеть (2, 1) в результатах. Где (2, 1) в вашем ответе? - person P_Rein; 30.03.2017
comment
Комбинация (2, 1) и (1, 2) — это один и тот же чувак. - person saimadhu.polamuri; 03.04.2017
comment
Несмотря на то, что в вопросе есть комбинации, имеются в виду перестановки. Прочтите его до конца и убедитесь, что от OP ожидаются как (2, 1), так и (1, 2). - person P_Rein; 03.04.2017

Вы ищете itertools.permutations?

От help(itertools.permutations),

Help on class permutations in module itertools:

class permutations(__builtin__.object)
 |  permutations(iterable[, r]) --> permutations object
 |  
 |  Return successive r-length permutations of elements in the iterable.
 |  
 |  permutations(range(3), 2) --> (0,1), (0,2), (1,0), (1,2), (2,0), (2,1)

Образец кода :

>>> from itertools import permutations
>>> stuff = [1, 2, 3]
>>> for i in range(0, len(stuff)+1):
        for subset in permutations(stuff, i):
               print(subset)


()
(1,)
(2,)
(3,)
(1, 2)
(1, 3)
(2, 1)
(2, 3)
(3, 1)
(3, 2)
(1, 2, 3)
(1, 3, 2)
(2, 1, 3)
(2, 3, 1)
(3, 1, 2)
(3, 2, 1)

Из Википедии разница между перестановками и комбинациями:

Перестановка:

Неформально перестановка набора объектов представляет собой расположение этих объектов в определенном порядке. Например, существует шесть перестановок множества {1,2,3}, а именно (1,2,3), (1,3,2), (2,1,3), (2,3,1) , (3,1,2) и (3,2,1).

Комбинация:

В математике комбинация — это способ выбора нескольких вещей из большей группы, где (в отличие от перестановок) порядок не имеет значения.

person Sukrit Kalra    schedule 02.07.2013

Вот решение без itertools

Сначала давайте определим перевод между индикаторным вектором 0 и 1s и подсписком (1, если элемент находится в подсписке)

def indicators2sublist(indicators,arr):
   return [item for item,indicator in zip(arr,indicators) if int(indicator)==1]

Затем нужно определить отображение числа между 0 и 2^n-1 в его двоичное векторное представление (используя строковую функцию format):

def bin(n,sz):
   return ('{d:0'+str(sz)+'b}').format(d=n)

Все, что нам осталось сделать, это перебрать все возможные числа и вызвать indicators2sublist

def all_sublists(arr):
  sz=len(arr)
  for n in xrange(0,2**sz):
     b=bin(n,sz)
     yield indicators2sublist(b,arr)
person Uri Goren    schedule 06.11.2016

itertools.permutations будет тем, что вы хотите. По математическому определению порядок для combinations не имеет значения, то есть (1,2) считается идентичным (2,1). В то время как с permutations каждый отдельный порядок считается уникальной перестановкой, поэтому (1,2) и (2,1) совершенно разные.

person Brien    schedule 02.07.2013

Я предполагаю, что вам нужны все возможные комбинации как «наборы» значений. Вот кусок кода, который я написал, который может помочь вам понять:

def getAllCombinations(object_list):
    uniq_objs = set(object_list)
    combinations = []
    for obj in uniq_objs:
        for i in range(0,len(combinations)):
            combinations.append(combinations[i].union([obj]))
        combinations.append(set([obj]))
return combinations

Вот пример:

combinations = getAllCombinations([20,10,30])
combinations.sort(key = lambda s: len(s))
print combinations
... [set([10]), set([20]), set([30]), set([10, 20]), set([10, 30]), set([20, 30]), set([10, 20, 30])]

Я думаю, что это имеет n! временная сложность, так что будьте осторожны. Это работает, но может быть не самым эффективным

person Shashank Singh    schedule 21.07.2016

просто подумал, что поместил бы это там, так как я не мог определить КАЖДЫЙ возможный результат, и имея в виду, что у меня есть только самые базовые знания, когда дело доходит до python, и, вероятно, есть гораздо более элегантное решение... (также извините плохие имена переменных

тестирование = [1, 2, 3]

тестирование2= [0]

n = -1

def testingSomethingElse(число):

try:

    testing2[0:len(testing2)] == testing[0]

    n = -1

    testing2[number] += 1

except IndexError:

    testing2.append(testing[0])

пока верно:

n += 1

testing2[0] = testing[n]

print(testing2)

if testing2[0] == testing[-1]:

    try:

        n = -1

        testing2[1] += 1

    except IndexError:

        testing2.append(testing[0])

    for i in range(len(testing2)):

        if testing2[i] == 4:

            testingSomethingElse(i+1)

            testing2[i] = testing[0]

мне сошло с рук == 4, потому что я работаю с целыми числами, но вам, возможно, придется изменить это соответствующим образом...

person Matt Slap    schedule 13.05.2017