목록 요소의 가능한 모든 조합을 얻는 방법은 무엇입니까?


423

나는 15 개의 숫자가있는 목록을 가지고 있으며 그 숫자의 32,768 조합을 모두 생성하는 코드를 작성해야합니다.

코드를 찾았 습니다 찾고있는 것을 분명히하는 (구글링에 의해)를 찾았지만 코드가 상당히 불투명하고 사용하는 것에주의를 기울였습니다. 또한 더 우아한 솔루션이 있어야한다고 생각합니다.

나에게 발생하는 유일한 일은 십진 정수 1-32768을 반복하여 이진수로 변환하고 이진 표현을 필터로 사용하여 적절한 숫자를 선택하는 것입니다.

누구든지 더 나은 방법을 알고 있습니까? 사용 map(), 아마?


9
독자들은 목록 항목이 고유 한지 여부 가 매우 중요한 고려 사항이라는 점에 유의해야합니다. 많은 알고리즘이 일부 하위 집합을 초과하게됩니다 (예 : 'abccc'-> [ '', 'a', 'b', 'c', 'c' , 'c', 'ac', 'ac', 'ac', ...] 쉬운 해결 방법은 순열을 얻기 전에 세트의 모든 요소를 ​​밀어 넣는 것입니다.
ninjagecko

@ninjagecko Set 라이브러리를 사용하는 것은 각각 O (n)이기 때문에 효율적이지 않습니다. 따라서 n 함수를 세트에 추가하는 것은 실제로 O (n ^ 2)입니다!
Scott Biggs

주의 깊게 질문을 읽은 결과, OP는 모든 조합이 아니라 15 개의 숫자 목록 중 PowerSet 을 요구하는 것 같습니다 . 나는 이것이 왜 대답이 가능한지 생각합니다.
스콧 빅스

@ 스콧 빅스 : 여기 파이썬에 대해 확신하고 있습니까? 집합 삽입 및 조회는 평균 O (1)입니다. 그것들은 사전과 같습니다. 그들은 해싱을 사용합니다. 파이썬에는 특별한 세트 라이브러리가 없습니다 (표준 라이브러리에 있습니다). 함수가 아닌 숫자를 여기에 삽입하고 있습니다. (O (2 ^ n) 메모리를 사용하는 것은 여전히 ​​비효율적입니다. 파워 셋이 아닌 조합을 원하는 사람들에게 적합한 솔루션은 단순한 재귀 적 구현 또는 product등입니다.)
ninjagecko

답변:


466

itertools.combinations를 살펴보십시오 .

itertools.combinations(iterable, r)

입력 iterable에서 요소의 r 길이 하위 시퀀스를 반환합니다.

조합은 사전 식 정렬 순서로 방출됩니다. 따라서 입력 반복 가능 항목이 정렬되면 조합 튜플이 정렬 된 순서로 생성됩니다.

2.6부터 배터리가 포함되어 있습니다!


31
모두 나열하면됩니다. list(itertools.combinations(iterable, r))
silgon

1
필요하지 않은 것 r, 즉 요소의 길이 하위 시퀀스의 조합.
mLstudent33

630

이 답변 은 한 가지 측면을 놓쳤습니다. OP는 길이 "r"의 조합뿐만 아니라 모든 조합을 요구했습니다.

따라서 모든 길이 "L"을 반복해야합니다.

import itertools

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

또는-만약 당신이 멋진 것을 원한다면 (또는 당신의 코드를 읽는 사람의 두뇌를 구부리려면) "combinations ()"생성기 체인을 생성하고 그것을 통해 반복 할 수 있습니다 :

from itertools import chain, combinations
def all_subsets(ss):
    return chain(*map(lambda x: combinations(ss, x), range(0, len(ss)+1)))

for subset in all_subsets(stuff):
    print(subset)

42
도와 주셔서 감사합니다! 위의 답변을 게시 한 후 몇 주 동안 Ben이 찾고있는 개념의 이름은 원래 15 개 항목의 "파워 셋"이라는 것을 알았습니다. 실제로 구현 예는 표준 파이썬 "itertools"문서 페이지 docs.python.org/library/itertools.html("powerset "의 grep)에서 제공됩니다.
Dan H

38
이 기사를 읽는 사람이라면 : 문서powerset() 의 레시피 섹션에있는 생성기 기능 은 더 단순하고 잠재적으로 적은 메모리를 사용하며 여기에 표시된 구현보다 더 빠를 것입니다. itertools
martineau

사전 조합 순서로 모든 조합을 생성 할 수 있습니까?
guik

@ guik : 99 % itertools.combinations가 목록의 항목 순서 를 유지 한다고 확신합니다 . 따라서 입력이 사전 순으로 정렬되면 각 출력도 나옵니다.
Dan H

예, itertools.combinations사전 조합 순서로 n 중 k의 조합을 생성하지만 n 중 k 까지의 모든 조합을 생성하지는 않습니다 . k 까지의powerset 모든 조합 생성 하지만 사전 식 순서대로 이해하지 않는 한 powerset ([1,2])-> [(), (1,), (2,), (1, 2)] . 해서는 안됩니다 : [(), (1,), (1, 2), (2,)]?
guik

52

itertools를 사용하는 게으른 원 라이너가 있습니다.

from itertools import compress, product

def combinations(items):
    return ( set(compress(items,mask)) for mask in product(*[[0,1]]*len(items)) )
    # alternative:                      ...in product([0,1], repeat=len(items)) )

이 답변의 기본 개념은 길이가 N 인 이진 문자열의 수와 동일한 2 ^ N 조합입니다. 각 이진 문자열에 대해 "1"에 해당하는 모든 요소를 ​​선택합니다.

items=abc * mask=###
 |
 V
000 -> 
001 ->   c
010 ->  b
011 ->  bc
100 -> a
101 -> a c
110 -> ab
111 -> abc

고려해야 할 사항 :

  • 이것은 당신이 호출 할 수 있어야 len(...)items있는 경우 : 해결 방법 ( items발전기와 같은 반복 가능한 같은 것입니다, 먼저 목록으로 바꿀items=list(_itemsArg) )
  • 이를 위해서는 반복 순서가 items 가 무작위가 아니어야합니다 (해결 방법 : 제정신이 아닙니다).
  • 이 항목은 고유의, 또는 다른 것을 요구 {2,2,1}하고 {2,1,1}에 모두 붕괴 할 것이다 {2,1}(: 사용 해결 collections.Counter드롭 인 교체 등을 set, 나중에 사용해야 할 수도 있지만이 ... 기본적으로 MULTISET의 tuple(sorted(Counter(...).elements()))당신이 해쉬 할 필요하면)

데모

>>> list(combinations(range(4)))
[set(), {3}, {2}, {2, 3}, {1}, {1, 3}, {1, 2}, {1, 2, 3}, {0}, {0, 3}, {0, 2}, {0, 2, 3}, {0, 1}, {0, 1, 3}, {0, 1, 2}, {0, 1, 2, 3}]

>>> list(combinations('abcd'))
[set(), {'d'}, {'c'}, {'c', 'd'}, {'b'}, {'b', 'd'}, {'c', 'b'}, {'c', 'b', 'd'}, {'a'}, {'a', 'd'}, {'a', 'c'}, {'a', 'c', 'd'}, {'a', 'b'}, {'a', 'b', 'd'}, {'a', 'c', 'b'}, {'a', 'c', 'b', 'd'}]

46

@Dan H 의 높은지지를받은 답변 아래, Dan 자신을 포함한 문서powerset()레시피에 대한 언급이 있습니다. 그러나 지금까지 아무도 답변으로 게시하지 않았습니다. 문제에 대한 최선의 접근 방법은 아니지만 더 나은 방법 중 하나 일 수 있으며 다른 의견 자가 약간의 격려 를 받으면 아래에 나와 있습니다. 이 함수는 가능한 모든 길이 의 목록 요소 (0 및 모든 요소를 ​​포함하는 요소 포함)의 고유 한 모든 조합을 생성 합니다 .itertools

참고 : 미묘하게 다른 목표가 고유 한 요소의 조합 만 얻는 것이라면 행 s = list(iterable)을 변경하여 s = list(set(iterable))중복 요소를 제거하십시오. 그럼에도 불구하고 iterable궁극적으로 list이것이 다른 여러 답변과 달리 발전기와 함께 작동 하는 수단 으로 바뀐다는 사실 .

from itertools import chain, combinations

def powerset(iterable):
    "powerset([1,2,3]) --> () (1,) (2,) (3,) (1,2) (1,3) (2,3) (1,2,3)"
    s = list(iterable)  # allows duplicate elements
    return chain.from_iterable(combinations(s, r) for r in range(len(s)+1))

stuff = [1, 2, 3]
for i, combo in enumerate(powerset(stuff), 1):
    print('combo #{}: {}'.format(i, combo))

산출:

combo #1: ()
combo #2: (1,)
combo #3: (2,)
combo #4: (3,)
combo #5: (1, 2)
combo #6: (1, 3)
combo #7: (2, 3)
combo #8: (1, 2, 3)

list()처음 에는 어떤 전환이 있습니까?
AMC

@Alexander : iterable의 길이를 결정할 수 있습니다.
martineau

36

다음은 재귀를 사용하는 것입니다.

>>> import copy
>>> def combinations(target,data):
...     for i in range(len(data)):
...         new_target = copy.copy(target)
...         new_data = copy.copy(data)
...         new_target.append(data[i])
...         new_data = data[i+1:]
...         print new_target
...         combinations(new_target,
...                      new_data)
...                      
... 
>>> target = []
>>> data = ['a','b','c','d']
>>> 
>>> combinations(target,data)
['a']
['a', 'b']
['a', 'b', 'c']
['a', 'b', 'c', 'd']
['a', 'b', 'd']
['a', 'c']
['a', 'c', 'd']
['a', 'd']
['b']
['b', 'c']
['b', 'c', 'd']
['b', 'd']
['c']
['c', 'd']
['d']

인쇄하는 대신 목록 목록을 반환하도록 수정할 수 있습니까?
James Vickery

@JamesVickery 예, 함수 외부에서 목록을 작성하고 추가하는 것을 보거나 (더 나은) 함수를 생성기로 만들거나 'yield'키워드를 살펴보십시오.)
Dangercrow

new_data = copy.copy(data)-이 행은 내가 아는 한 중복되지 않으며 아무 것도 영향을 미치지 않습니다.
Dmitriy Fialkovskiy

31

이 단일 라이너는 모든 조합 ( 원래 목록 / 세트에 고유 한 요소 가 포함 된 경우 0n항목 간 n)을 제공하고 기본 메소드를 사용합니다.itertools.combinations .

파이썬 2

from itertools import combinations

input = ['a', 'b', 'c', 'd']

output = sum([map(list, combinations(input, i)) for i in range(len(input) + 1)], [])

파이썬 3

from itertools import combinations

input = ['a', 'b', 'c', 'd']

output = sum([list(map(list, combinations(input, i))) for i in range(len(input) + 1)], [])

출력은 다음과 같습니다.

[[],
 ['a'],
 ['b'],
 ['c'],
 ['d'],
 ['a', 'b'],
 ['a', 'c'],
 ['a', 'd'],
 ['b', 'c'],
 ['b', 'd'],
 ['c', 'd'],
 ['a', 'b', 'c'],
 ['a', 'b', 'd'],
 ['a', 'c', 'd'],
 ['b', 'c', 'd'],
 ['a', 'b', 'c', 'd']]

온라인으로 사용해보십시오 :

http://ideone.com/COghfX


이것은 순열입니다
AdHominem

15
@AdHominem : 아닙니다. 아닙니다. 모든 조합의 목록입니다. 치환은 예를 들어을 포함 할 것이다 ['b', 'a'].
naught101

TypeError: can only concatenate list (not "map") to list
0x48piraj

@ 0x48piraj : 알려 주셔서 감사합니다. 결과적으로 내 답변을 편집했습니다!
Mathieu Rodic

21

본인은 Ben이 실제로 모든 조합을 요청한 Dan H에 동의합니다 . itertools.combinations()모든 조합을 제공하지는 않습니다.

또 다른 문제는 입력 iterable이 큰 경우 목록의 모든 것 대신 생성기를 반환하는 것이 좋습니다.

iterable = range(10)
for s in xrange(len(iterable)+1):
  for comb in itertools.combinations(iterable, s):
    yield comb

1
좋은 예입니다. 나는 발전기를 좋아하고 ... 파이썬을 좋아합니다! 이 예제에는 한 번에 하나의 combinations () 객체 만 있고 한 번에 조합 중 하나를 생성합니다. (어쩌면 사용 예제 로이 주위에 def 블록을 추가하고 싶을 것입니다.) 내 구현 (위의 chain () 사용)은 그리 나쁘지 않습니다. 한 번 ...하지만 내 이해에 따르면 체인은 후속 생성기에서 첫 번째 생성기를 "사용"하므로 한 번에 2 ** len (iterable) 조합을 모두 생성하지는 않습니다.
Dan H

18

이것은 재귀를 지원하는 모든 프로그래밍 언어 (itertools, yield, list comprehension)없이 쉽게 전달할 수있는 접근 방식입니다 .

def combs(a):
    if len(a) == 0:
        return [[]]
    cs = []
    for c in combs(a[1:]):
        cs += [c, c+[a[0]]]
    return cs

>>> combs([1,2,3,4,5])
[[], [1], [2], [2, 1], [3], [3, 1], [3, 2], ..., [5, 4, 3, 2, 1]]

아! 좋은 구현. Prolog에서 HEAD = a [0], TAIL = a [1 :]을 인식합니다. 또는 Lisp의 car = a [0], cdr = a [1 :]입니다. 여기서 메모를 사용할 수 있는지 궁금합니다.
Javier Ruiz

진실. 목록 슬라이싱은 O (k)입니다. 여기서 k는 슬라이스의 길이입니다. 나는 첫 번째를 제외한 모든 실행에서 O (1)을 만드는 맵에서 조회를 수행 하여이 속도를 높일 수 있다고 생각합니다. 이 구현은 성능을 위해 참조되지 않아야합니다. 이를 위해 더 나은 구현이 존재합니다. 이 구현은 대부분의 다른 언어로의 단순성과 이식성을위한 것입니다.
Jonathan R

14

이 간단한 코드를 사용하여 파이썬에서 목록의 모든 조합을 생성 할 수 있습니다

import itertools

a = [1,2,3,4]
for i in xrange(0,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)]

이 코드의 버그 : 빈 세트를 반환하지 않습니다. xrange (0, ...)를 의미 할 수도 있지만 테스트되지 않았습니다. 편집 : 나는 그것을 고치기 위해 대답을 편집했다.
ninjagecko

13

itertools 또는 다른 추가 라이브러리를 가져 오지 않고 답변을 원하는 사람들을 위해이 기능을 추가 할 것이라고 생각했습니다.

def powerSet(items):
    """
    Power set generator: get all possible combinations of a list’s elements

    Input:
        items is a list
    Output:
        returns 2**n combination lists one at a time using a generator 

    Reference: edx.org 6.00.2x Lecture 2 - Decision Trees and dynamic programming
    """

    N = len(items)
    # enumerate the 2**N possible combinations
    for i in range(2**N):
        combo = []
        for j in range(N):
            # test bit jth of integer i
            if (i >> j) % 2 == 1:
                combo.append(items[j])
        yield combo

간단한 수율 생성기 사용법 :

for i in powerSet([1,2,3,4]):
    print (i, ", ",  end="")

위 사용 예의 출력 :

[], [1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3], [4], [1, 4] , [2, 4], [1, 2, 4], [3, 4], [1, 3, 4], [2, 3, 4], [1, 2, 3, 4],


나는 이것이 매우 깔끔한 해결책이라고 생각합니다.
greentec

8

여기에 itertools.combinations함수 사용과 관련된 또 다른 솔루션 (한 줄짜리)이 있지만 여기서는 for 루프 또는 합계와 달리 이중 목록 이해를 사용합니다.

def combs(x):
    return [c for i in range(len(x)+1) for c in combinations(x,i)]

데모:

>>> combs([1,2,3,4])
[(), 
 (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)]

5
from itertools import permutations, combinations


features = ['A', 'B', 'C']
tmp = []
for i in range(len(features)):
    oc = combinations(features, i + 1)
    for c in oc:
        tmp.append(list(c))

산출

[
 ['A'],
 ['B'],
 ['C'],
 ['A', 'B'],
 ['A', 'C'],
 ['B', 'C'],
 ['A', 'B', 'C']
]

4

아래는 다른 유사한 답변 https://stackoverflow.com/a/23743696/711085 와 유사한 "표준 재귀 답변"입니다. 입니다. (N! 순열을 모두 처리 할 수있는 방법이 없기 때문에 실제로 스택 공간 부족에 대해 걱정할 필요가 없습니다.)

모든 요소를 ​​차례로 방문하여 가져 오거나 떠납니다 (이 알고리즘에서 2 ^ N 카디널리티를 직접 볼 수 있음).

def combs(xs, i=0):
    if i==len(xs):
        yield ()
        return
    for c in combs(xs,i+1):
        yield c
        yield c+(xs[i],)

데모:

>>> list( combs(range(5)) )
[(), (0,), (1,), (1, 0), (2,), (2, 0), (2, 1), (2, 1, 0), (3,), (3, 0), (3, 1), (3, 1, 0), (3, 2), (3, 2, 0), (3, 2, 1), (3, 2, 1, 0), (4,), (4, 0), (4, 1), (4, 1, 0), (4, 2), (4, 2, 0), (4, 2, 1), (4, 2, 1, 0), (4, 3), (4, 3, 0), (4, 3, 1), (4, 3, 1, 0), (4, 3, 2), (4, 3, 2, 0), (4, 3, 2, 1), (4, 3, 2, 1, 0)]

>>> list(sorted( combs(range(5)), key=len))
[(), 
 (0,), (1,), (2,), (3,), (4,), 
 (1, 0), (2, 0), (2, 1), (3, 0), (3, 1), (3, 2), (4, 0), (4, 1), (4, 2), (4, 3), 
 (2, 1, 0), (3, 1, 0), (3, 2, 0), (3, 2, 1), (4, 1, 0), (4, 2, 0), (4, 2, 1), (4, 3, 0), (4, 3, 1), (4, 3, 2), 
 (3, 2, 1, 0), (4, 2, 1, 0), (4, 3, 1, 0), (4, 3, 2, 0), (4, 3, 2, 1), 
 (4, 3, 2, 1, 0)]

>>> len(set(combs(range(5))))
32

2

목록 이해 사용하기 :

def selfCombine( list2Combine, length ):
    listCombined = str( ['list2Combine[i' + str( i ) + ']' for i in range( length )] ).replace( "'", '' ) \
                     + 'for i0 in range(len( list2Combine ) )'
    if length > 1:
        listCombined += str( [' for i' + str( i ) + ' in range( i' + str( i - 1 ) + ', len( list2Combine ) )' for i in range( 1, length )] )\
            .replace( "', '", ' ' )\
            .replace( "['", '' )\
            .replace( "']", '' )

    listCombined = '[' + listCombined + ']'
    listCombined = eval( listCombined )

    return listCombined

list2Combine = ['A', 'B', 'C']
listCombined = selfCombine( list2Combine, 2 )

결과는 다음과 같습니다.

['A', 'A']
['A', 'B']
['A', 'C']
['B', 'B']
['B', 'C']
['C', 'C']

4
이 제안은 문자열 맹 글링을 통해 세트를 만드는 것입니까?!?! 이런 까마귀 .... 그리고 : 그것은 집합을 반환하지 않고 오히려 combinations_with_replacement ()와 같은 것을 반환합니다. ( docs.python.org/library/… 참조 )
Dan H

이것은 실제로 combination_with_replacement () 와 동일 하지만 적어도 내 상자에서는 itertools 보다 약간 빠르게 실행됩니다 . 내가 말할 수있는 것은 목록 이해력이 좋아.
zmk

1
응답 해주셔서 감사합니다! [ 'A', 'A'], [ 'A', 'B'], [ 'A', 'C'], [ 'B', 'A'], [ 'B', 'B'], [ 'B', 'C'], [ 'C', 'A'], [ 'C', 'B'] 및 [ 'C', 'C'] 모두?
Karyo

매우 흥미롭지 만 파이썬은 여기서 미묘한 부분을 이해하지 못합니다. 다른 범위에서 listCombined를 사용하고 for 루프가 모두 한 줄에 있다는 사실에 특별한 것이 있습니까? 운이 좋으면 이것을 Java로 이식하려고합니다.
Scott Biggs

2

이 코드는 중첩 목록이있는 간단한 알고리즘을 사용합니다.

# FUNCTION getCombos: To generate all combos of an input list, consider the following sets of nested lists...
#
#           [ [ [] ] ]
#           [ [ [] ], [ [A] ] ]
#           [ [ [] ], [ [A],[B] ],         [ [A,B] ] ]
#           [ [ [] ], [ [A],[B],[C] ],     [ [A,B],[A,C],[B,C] ],                   [ [A,B,C] ] ]
#           [ [ [] ], [ [A],[B],[C],[D] ], [ [A,B],[A,C],[B,C],[A,D],[B,D],[C,D] ], [ [A,B,C],[A,B,D],[A,C,D],[B,C,D] ], [ [A,B,C,D] ] ]
#
#  There is a set of lists for each number of items that will occur in a combo (including an empty set).
#  For each additional item, begin at the back of the list by adding an empty list, then taking the set of
#  lists in the previous column (e.g., in the last list, for sets of 3 items you take the existing set of
#  3-item lists and append to it additional lists created by appending the item (4) to the lists in the
#  next smallest item count set. In this case, for the three sets of 2-items in the previous list. Repeat
#  for each set of lists back to the initial list containing just the empty list.
#

def getCombos(listIn = ['A','B','C','D','E','F'] ):
    listCombos = [ [ [] ] ]     # list of lists of combos, seeded with a list containing only the empty list
    listSimple = []             # list to contain the final returned list of items (e.g., characters)

    for item in listIn:
        listCombos.append([])   # append an emtpy list to the end for each new item added
        for index in xrange(len(listCombos)-1, 0, -1):  # set the index range to work through the list
            for listPrev in listCombos[index-1]:        # retrieve the lists from the previous column
                listCur = listPrev[:]                   # create a new temporary list object to update
                listCur.append(item)                    # add the item to the previous list to make it current
                listCombos[index].append(listCur)       # list length and append it to the current list

                itemCombo = ''                          # Create a str to concatenate list items into a str
                for item in listCur:                    # concatenate the members of the lists to create
                    itemCombo += item                   # create a string of items
                listSimple.append(itemCombo)            # add to the final output list

    return [listSimple, listCombos]
# END getCombos()

따라서이 코드는 [listOfCombinations, listOfCombinationsGroupedBySize]를 반환합니다. 불행히도 데모 입력으로 실행하면 64가 아닌 63 개의 요소가 제공됩니다. 빈 세트가 누락 된 것 같습니다 (이 경우 빈 문자열 "").
ninjagecko

2

itertools를 사용하여 모든 조합 을 얻는 것이 훨씬 실용적이라는 것을 알고 있지만 원하는 경우 많은 코드를 작성하려는 경우 목록 이해 만으로이 부분을 ​​달성 할 수 있습니다

두 쌍의 조합 :

    lambda l: [(a, b) for i, a in enumerate(l) for b in l[i+1:]]


그리고 세 쌍의 조합의 경우 다음과 같이 쉽습니다.

    lambda l: [(a, b, c) for i, a in enumerate(l) for ii, b in enumerate(l[i+1:]) for c in l[i+ii+2:]]


결과는 itertools.combinations를 사용하는 것과 같습니다.

import itertools
combs_3 = lambda l: [
    (a, b, c) for i, a in enumerate(l) 
    for ii, b in enumerate(l[i+1:]) 
    for c in l[i+ii+2:]
]
data = ((1, 2), 5, "a", None)
print("A:", list(itertools.combinations(data, 3)))
print("B:", combs_3(data))
# A: [((1, 2), 5, 'a'), ((1, 2), 5, None), ((1, 2), 'a', None), (5, 'a', None)]
# B: [((1, 2), 5, 'a'), ((1, 2), 5, None), ((1, 2), 'a', None), (5, 'a', None)]

2

itertools를 사용하지 않고 :

def combine(inp):
    return combine_helper(inp, [], [])


def combine_helper(inp, temp, ans):
    for i in range(len(inp)):
        current = inp[i]
        remaining = inp[i + 1:]
        temp.append(current)
        ans.append(tuple(temp))
        combine_helper(remaining, temp, ans)
        temp.pop()
    return ans


print(combine(['a', 'b', 'c', 'd']))

2

다음은 두 가지 구현입니다. itertools.combinations

리스트를 돌려주는 것

def combinations(lst, depth, start=0, items=[]):
    if depth <= 0:
        return [items]
    out = []
    for i in range(start, len(lst)):
        out += combinations(lst, depth - 1, i + 1, items + [lst[i]])
    return out

하나는 발전기를 반환

def combinations(lst, depth, start=0, prepend=[]):
    if depth <= 0:
        yield prepend
    else:
        for i in range(start, len(lst)):
            for c in combinations(lst, depth - 1, i + 1, prepend + [lst[i]]):
                yield c

prepend 인수는 정적이며 모든 호출에서 변경되지 않으므로 도우미 기능을 제공하는 것이 좋습니다.

print([c for c in combinations([1, 2, 3, 4], 3)])
# [[1, 2, 3], [1, 2, 4], [1, 3, 4], [2, 3, 4]]

# get a hold of prepend
prepend = [c for c in combinations([], -1)][0]
prepend.append(None)

print([c for c in combinations([1, 2, 3, 4], 3)])
# [[None, 1, 2, 3], [None, 1, 2, 4], [None, 1, 3, 4], [None, 2, 3, 4]]

이것은 매우 피상적이지만 미안보다 안전합니다.


2

어떻습니까 ..리스트 대신 문자열을 사용했지만 같은 것은 .. 문자열은 파이썬에서리스트처럼 취급 될 수 있습니다.

def comb(s, res):
    if not s: return
    res.add(s)
    for i in range(0, len(s)):
        t = s[0:i] + s[i + 1:]
        comb(t, res)

res = set()
comb('game', res) 

print(res)

2

itertools의 조합

import itertools
col_names = ["aa","bb", "cc", "dd"]
all_combinations = itertools.chain(*[itertools.combinations(col_names,i+1) for i,_ in enumerate(col_names)])
print(list(all_combinations))

감사


2

itertoolsPython 3이 없으면 다음과 같이 할 수 있습니다.

def combinations(arr, carry):
    for i in range(len(arr)):
        yield carry + arr[i]
        yield from combinations(arr[i + 1:], carry + arr[i])

처음에는 carry = "".


2

3 가지 기능 :

  1. n 개의 원소리스트의 모든 조합
  2. 순서가 명확하지 않은 n 요소의 모든 조합 목록
  3. 모든 순열
import sys

def permutations(a):
    return combinations(a, len(a))

def combinations(a, n):
    if n == 1:
        for x in a:
            yield [x]
    else:
        for i in range(len(a)):
            for x in combinations(a[:i] + a[i+1:], n-1):
                yield [a[i]] + x

def combinationsNoOrder(a, n):
    if n == 1:
        for x in a:
            yield [x]
    else:
        for i in range(len(a)):
            for x in combinationsNoOrder(a[:i], n-1):
                yield [a[i]] + x

if __name__ == "__main__":
    for s in combinations(list(map(int, sys.argv[2:])), int(sys.argv[1])):
        print(s)

나는 이것을 매우 좋아한다 !!! 감사합니다!!! 파이썬의 조합 함수는 조금 이상합니다. 수학에서 "콤비네이션"기능은 변형이며 "combinationsNoOrder"는 실제로 조합입니다. 나는 이번에 나에게했던 것처럼 수학의 지점에서 파이썬으로 오는 사람들을 혼란스럽게 생각합니다. 어쨌든 좋은 솔루션, 많은 이익을 주셔서 감사합니다!
Đumić Branislav

1

이것은 내 구현입니다

    def get_combinations(list_of_things):
    """gets every combination of things in a list returned as a list of lists

    Should be read : add all combinations of a certain size to the end of a list for every possible size in the
    the list_of_things.

    """
    list_of_combinations = [list(combinations_of_a_certain_size)
                            for possible_size_of_combinations in range(1,  len(list_of_things))
                            for combinations_of_a_certain_size in itertools.combinations(list_of_things,
                                                                                         possible_size_of_combinations)]
    return list_of_combinations

1
여기에 게시 된 이전 구현보다 더 나은 해결 방법은 무엇입니까?
user1767754

0

당신은 또한 사용할 수있는 파워 셋의 우수한에서 기능을 more_itertools패키지로 제공된다.

from more_itertools import powerset

l = [1,2,3]
list(powerset(l))

# [(), (1,), (2,), (3,), (1, 2), (1, 3), (2, 3), (1, 2, 3)]

OP의 요구 사항을 충족하는지 확인할 수도 있습니다.

from more_itertools import ilen

assert ilen(powerset(range(15))) == 32_768

-1
def combinations(iterable, r):
# combinations('ABCD', 2) --> AB AC AD BC BD CD
# combinations(range(4), 3) --> 012 013 023 123
pool = tuple(iterable)
n = len(pool)
if r > n:
    return
indices = range(r)
yield tuple(pool[i] for i in indices)
while True:
    for i in reversed(range(r)):
        if indices[i] != i + n - r:
            break
    else:
        return
    indices[i] += 1
    for j in range(i+1, r):
        indices[j] = indices[j-1] + 1
    yield tuple(pool[i] for i in indices)


x = [2, 3, 4, 5, 1, 6, 4, 7, 8, 3, 9]
for i in combinations(x, 2):
    print i

1
내가 옳다면, 이것은 파이썬 문서 [ docs.python.org/3.6/library/itertools.html ] 에서 복사 한 정확한 코드 입니다. 그렇다면 소스를 참조하십시오.
GabrielChu

흥미로운 접근
pelos

-1

누군가가 반대로 목록을 찾고 있다면 :

stuff = [1, 2, 3, 4]

def reverse(bla, y):
    for subset in itertools.combinations(bla, len(bla)-y):
        print list(subset)
    if y != len(bla):
        y += 1
        reverse(bla, y)

reverse(stuff, 1)

-1
flag = 0
requiredCals =12
from itertools import chain, combinations

def powerset(iterable):
    s = list(iterable)  # allows duplicate elements
    return chain.from_iterable(combinations(s, r) for r in range(len(s)+1))

stuff = [2,9,5,1,6]
for i, combo in enumerate(powerset(stuff), 1):
    if(len(combo)>0):
        #print(combo , sum(combo))
        if(sum(combo)== requiredCals):
            flag = 1
            break
if(flag==1):
    print('True')
else:
    print('else')
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.