Làm thế nào để có được tất cả các kết hợp có thể có của các yếu tố của danh sách?


423

Tôi có một danh sách với 15 số và tôi cần viết một số mã tạo ra tất cả 32.768 kết hợp của các số đó.

Tôi đã tìm thấy một số mã (bởi Googling) rõ ràng là những gì tôi đang tìm kiếm, nhưng tôi thấy mã này khá mờ và cảnh giác khi sử dụng nó. Thêm vào đó tôi có cảm giác phải có một giải pháp thanh lịch hơn.

Điều duy nhất xảy ra với tôi là chỉ cần lặp qua các số nguyên thập phân 1 mật32768 và chuyển đổi chúng thành nhị phân và sử dụng biểu diễn nhị phân làm bộ lọc để chọn ra các số thích hợp.

Có ai biết một cách tốt hơn? Sử dụng map(), có thể?


9
Bạn đọc cần lưu ý rằng các mục danh sách có phải là duy nhất hay không là một điều cần cân nhắc, vì nhiều thuật toán sau đó sẽ vượt qua một số tập hợp con (ví dụ: 'abccc' -> ['', 'a', 'b', 'c', 'c' , 'c', 'ac', 'ac', 'ac', ...]. Một cách giải quyết dễ dàng là chỉ cần đẩy tất cả các thành phần trong một tập hợp trước khi có được hoán vị của chúng.
ninjagecko

@ninjagecko Sử dụng thư viện Set không hiệu quả vì mỗi cái đều tốt nhất là O (n). Do đó, thêm n hàm vào một tập thực sự là O (n ^ 2)!
Scott Biggie

Từ việc đọc kỹ câu hỏi, có vẻ như OP đang yêu cầu Power set trong danh sách 15 số của anh ấy, không phải tất cả các kết hợp. Tôi nghĩ rằng đây có thể là lý do tại sao các câu trả lời ở khắp mọi nơi.
Scott Biggie

@Scott Bigss: bạn có chắc là bạn đang dùng Python ở đây không? Đặt chèn và tra cứu là trường hợp trung bình O (1). Chúng giống như từ điển. Họ sử dụng băm. Python không có thư viện tập đặc biệt (nó nằm trong thư viện chuẩn). Chúng tôi đang chèn số ở đây không phải là chức năng. (Sẽ vẫn không hiệu quả khi sử dụng bộ nhớ O (2 ^ n); giải pháp phù hợp cho những người muốn kết hợp thay vì quyền hạn là một triển khai đệ quy đơn giản, hoặc product, v.v.)
ninjagecko

Câu trả lời:


467

Hãy xem itertools.combinations :

itertools.combinations(iterable, r)

Trả về chiều dài r của các phần tử từ lần lặp đầu vào.

Sự kết hợp được phát ra theo thứ tự từ điển. Vì vậy, nếu iterable đầu vào được sắp xếp, các bộ kết hợp sẽ được sản xuất theo thứ tự được sắp xếp.

Kể từ 2.6, pin được bao gồm!


31
bạn chỉ có thể liệt kê tất cả. list(itertools.combinations(iterable, r))
silgon

1
có bất cứ điều gì không yêu cầu r, tức là sự kết hợp của bất kỳ phần tử dài nào của các phần tử.
mLstudent33

630

Câu trả lời này đã bỏ qua một khía cạnh: OP yêu cầu TẤT CẢ các kết hợp ... không chỉ là kết hợp độ dài "r".

Vì vậy, bạn sẽ phải lặp qua tất cả các độ dài "L":

import itertools

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

Hoặc - nếu bạn muốn nhận được snazzy (hoặc uốn cong não của bất kỳ ai đọc mã của bạn sau bạn) - bạn có thể tạo chuỗi các trình tạo "kết hợp ()" và lặp lại thông qua đó:

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
Cảm ơn về sự hỗ trợ! Trong những tuần kể từ khi tôi đăng bài trả lời ở trên, tôi đã thấy rằng TÊN khái niệm cho những gì Ben đang tìm kiếm là "quyền hạn" của bộ 15 mục gốc. Trong thực tế, một thực hiện ví dụ được đưa ra trên python "itertools" trang doc tiêu chuẩn: docs.python.org/library/itertools.html (grep cho "Powerset").
Dân H

38
Đối với bất kỳ ai đọc đến nay: Hàm powerset()tạo trong phần công thức nấu ăn của itertoolstài liệu đơn giản hơn, có khả năng sử dụng ít bộ nhớ hơn và có khả năng nhanh hơn so với triển khai được hiển thị ở đây.
martineau

Có thể tạo ra tất cả các kết hợp theo thứ tự từ điển?
guik

@guik: Tôi chắc chắn 99% là itertools.combinationsgiữ nguyên thứ tự vật phẩm trong danh sách mà nó mang lại. Do đó, nếu đầu vào được sắp xếp theo từ vựng, thì mỗi đầu ra cũng sẽ như vậy.
Dan H

Có, itertools.combinationstạo ra các kết hợp k giữa n theo thứ tự từ điển, nhưng không phải tất cả các kết hợp lên đến k giữa n. powersettạo ra tất cả các kết hợp lên đến k, nhưng không theo thứ tự từ vựng theo như tôi hiểu: powerset ([1,2]) -> [(), (1,), (2,), (1, 2)] . Không nên là: [(), (1,), (1, 2), (2,)]?
guik

52

Đây là một kẻ lười biếng, cũng sử dụng 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)) )

Ý tưởng chính đằng sau câu trả lời này: có 2 ^ N kết hợp - giống như số chuỗi nhị phân có độ dài N. Với mỗi chuỗi nhị phân, bạn chọn tất cả các phần tử tương ứng với "1".

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

Những điều cần cân nhắc:

  • Điều này đòi hỏi rằng bạn có thể gọi len(...)vào items(workaround: nếu itemslà một cái gì đó giống như một iterable giống như một máy phát điện, biến nó thành một danh sách đầu tiên với items=list(_itemsArg))
  • Điều này đòi hỏi thứ tự lặp lại itemskhông phải là ngẫu nhiên (cách giải quyết: không được điên rồ)
  • Điều này đòi hỏi các mục này là duy nhất, hoặc nếu không {2,2,1}{2,1,1}cả hai sẽ sụp đổ {2,1}(cách giải quyết: sử dụng collections.Counternhư một sự thay thế thả vào set; về cơ bản nó là một multiset ... mặc dù sau này bạn có thể cần sử dụng tuple(sorted(Counter(...).elements()))nếu bạn cần nó có thể băm được)

Bản giới thiệu

>>> 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

Trong các bình luận dưới câu trả lời được đánh giá cao của @Dan H, đề cập đến được tạo ra từ powerset()công thức trong itertoolstài liệu của chính mình . Tuy nhiên , cho đến nay không ai đăng nó như một câu trả lời. Vì nó có lẽ là một trong những cách tốt hơn nếu không phải là cách tiếp cận tốt nhất cho vấn đề LỚN và được khuyến khích một chút từ một người bình luận khác, nó được hiển thị bên dưới. Chức năng sản xuất tất cả các kết hợp độc đáo của các yếu tố danh sách tất cả các chiều dài càng tốt (bao gồm cả những loại có chứa zero và tất cả các yếu tố).

Lưu ý : Nếu mục tiêu khác biệt một cách tinh tế là chỉ thu được các kết hợp các yếu tố duy nhất, thay đổi dòng s = list(iterable)thành s = list(set(iterable))để loại bỏ bất kỳ yếu tố trùng lặp nào. Bất kể, thực tế iterablelà cuối cùng biến thành một listphương tiện nó sẽ hoạt động với máy phát điện (không giống như một số câu trả lời khác).

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))

Đầu ra:

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)

Là gì list()chuyển đổi cho ở nơi đầu tiên?
AMC

@Alexander: Để cho phép xác định độ dài của vòng lặp.
martineau

36

Đây là một cách sử dụng đệ quy:

>>> 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']

Điều này có thể được sửa đổi để trả về một danh sách các danh sách thay vì in?
James Vickery

@JamesVickery vâng, bạn có thể xem một danh sách bên ngoài chức năng và nối thêm vào đó, hoặc (tốt hơn) làm cho chức năng trở thành một trình tạo, hãy xem từ khóa 'suất' :)
Dangercrow

new_data = copy.copy(data)- hàng này là dư thừa theo như tôi thấy, nó không ảnh hưởng đến bất cứ điều gì
Dmitriy Fialkovskiy

31

Lớp lót này cung cấp cho bạn tất cả các kết hợp (giữa 0ncác mục nếu danh sách / bộ gốc có chứa ncác phần tử riêng biệt) và sử dụng phương thức gốc itertools.combinations:

Con trăn 2

from itertools import combinations

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

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

Con trăn 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)], [])

Đầu ra sẽ là:

[[],
 ['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']]

Dùng thử trực tuyến:

http://ideone.com/COghfX


Đây là một hoán vị
AdHominem

15
@AdHominem: không, không phải vậy. Đó là một danh sách của tất cả các kết hợp. Hoán vị sẽ bao gồm, ví dụ ['b', 'a'].
ness101

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

@ 0x48piraj: cảm ơn bạn đã chú ý, do đó tôi đã chỉnh sửa câu trả lời của mình!
Mathieu Rodic

21

Tôi đồng ý với Dan H rằng Ben thực sự yêu cầu tất cả các kết hợp. itertools.combinations()không đưa ra tất cả các kết hợp.

Một vấn đề khác là, nếu iterable đầu vào lớn, có lẽ tốt hơn là trả về một trình tạo thay vì mọi thứ trong danh sách:

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

1
Ví dụ tốt đẹp. Tôi yêu máy phát điện ... và tôi yêu Python vì có chúng! Ví dụ này chỉ có một đối tượng kết hợp () xung quanh tại một thời điểm và mang lại một trong các kết hợp tại một thời điểm. (Có lẽ bạn muốn thêm khối def xung quanh điều này - như một ví dụ sử dụng.) Lưu ý rằng việc triển khai của tôi (với chuỗi (), được đưa ra ở trên) không quá tệ: thực sự tạo ra tất cả các trình tạo len (có thể lặp lại) một lần ... nhưng nó KHÔNG tạo ra tất cả 2 ** kết hợp len (có thể lặp lại) cùng một lúc, theo - theo hiểu biết của tôi - chuỗi "sử dụng" trình tạo đầu tiên trước khi vẽ từ các kết hợp tiếp theo.
Dan H

18

Đây là một cách tiếp cận có thể dễ dàng chuyển sang tất cả các ngôn ngữ lập trình hỗ trợ đệ quy (không itertools, không năng suất, không hiểu danh sách) :

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]]

Ah! Triển khai tốt. Tôi nhận ra HEAD = a [0], TAIL = a [1:] từ Prolog. Hoặc xe = a [0], cdr = a [1:] từ Lisp. Tôi tự hỏi nếu chúng ta có thể sử dụng ghi nhớ ở đây ...
Javier Ruiz

Thật. Danh sách cắt là O (k) trong đó k là chiều dài của lát. Tôi đoán người ta có thể tăng tốc độ này bằng cách tra cứu trên bản đồ sẽ làm cho nó O (1) trong tất cả các lần chạy trừ lần đầu tiên. Lưu ý rằng việc thực hiện này không nên được tham chiếu cho hiệu suất. Cho rằng thực hiện tốt hơn tồn tại. Việc triển khai này chỉ nhằm mục đích đơn giản và tính di động đối với hầu hết các ngôn ngữ khác.
Jonathan R

14

Bạn có thể tạo tất cả các kết hợp của một danh sách trong python bằng mã đơn giản này

import itertools

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

Kết quả sẽ là:

[()]
[(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)]

Lỗi trong mã này: không trả về tập hợp trống. Có thể có nghĩa là xrange (0, ...) nhưng chưa được thử nghiệm. chỉnh sửa : Tôi đã đi trước và chỉnh sửa câu trả lời của bạn để sửa nó.
ninjagecko

13

Tôi nghĩ rằng tôi sẽ thêm chức năng này cho những người tìm kiếm câu trả lời mà không cần nhập itertools hoặc bất kỳ thư viện bổ sung nào khác.

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

Cách sử dụng Trình tạo năng suất đơn giản:

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

Đầu ra từ ví dụ sử dụng ở trên:

[], [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],


Tôi nghĩ rằng đây là giải pháp rất gọn gàng.
greentec

8

Đây là một giải pháp khác (một lớp lót), liên quan đến việc sử dụng itertools.combinationshàm, nhưng ở đây chúng tôi sử dụng cách hiểu danh sách kép (trái ngược với vòng lặp for hoặc sum):

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

Bản giới thiệu:

>>> 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))

đầu ra

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

4

Dưới đây là "câu trả lời đệ quy tiêu chuẩn", tương tự như câu trả lời tương tự khác https://stackoverflow.com/a/23743696/711085 . (Chúng tôi thực sự không phải lo lắng về việc hết dung lượng ngăn xếp vì không có cách nào chúng tôi có thể xử lý tất cả các hoán vị N!)

Nó lần lượt truy cập mọi phần tử và lấy nó hoặc rời khỏi nó (chúng ta có thể thấy trực tiếp phần tử 2 ^ N từ thuật toán này).

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

Bản giới thiệu:

>>> 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

Sử dụng hiểu danh sách:

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 )

Đầu ra sẽ là:

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

4
Đề xuất này là thực hiện xâu chuỗi để xây dựng bộ?!?! Holy crow .... Và: nó không trả lại quyền hạn, mà là, một cái gì đó giống như tổ hợp_with numplocation (). (Xem docs.python.org/l Library / trộm )
Dan H

Điều này thực sự giống như kết hợp_with numplocation () , nhưng ít nhất trên hộp của tôi, nó chạy nhanh hơn itertools một chút . Tôi có thể nói gì, tôi thích danh sách hiểu.
zmk

1
Cảm ơn bạn đã trả lời! Điều gì về việc tạo danh sách Được kết hợp với các danh sách đảo ngược, chẳng hạn như ['A', 'A'], ['A', 'B'], ['A', 'C'], ['B', 'A'], [ 'B', 'B'], ['B', 'C'], ['C', 'A'], ['C', 'B'] và ['C', 'C'] bao gồm mọi điều?
Karyo

Rất thú vị, nhưng con trăn của tôi không hiểu lắm về sự tinh tế ở đây. Có điều gì đặc biệt về việc sử dụng listCombined trong các phạm vi khác nhau và thực tế là vòng lặp for là tất cả trong một dòng không? Tôi đang cố gắng chuyển cái này sang Java với một chút may mắn.
Scott Biggie

2

Mã này sử dụng một thuật toán đơn giản với các danh sách lồng nhau ...

# 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()

Vì vậy, những gì mã này dường như làm là trả về [listOfCombinating, listOfCombinatinggroupedBySize]. Thật không may khi chạy với đầu vào demo, nó cung cấp 63 phần tử thay vì 64; nó dường như thiếu tập hợp trống (trong trường hợp này là chuỗi rỗng "").
ninjagecko

2

Tôi biết rằng thực tế hơn nhiều khi sử dụng itertools để có được tất cả các kết hợp, nhưng bạn có thể đạt được phần này chỉ với việc hiểu danh sách nếu bạn thực sự mong muốn, với điều kiện bạn muốn viết mã nhiều

Đối với sự kết hợp của hai cặp:

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


Và, đối với sự kết hợp của ba cặp, thật dễ dàng như sau:

    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:]]


Kết quả giống hệt với việc sử dụng 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

Không sử dụng 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

Đây là hai triển khai itertools.combinations

Một danh sách trả về một danh sách

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

Một trả về một máy phát điện

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

Xin lưu ý rằng việc cung cấp chức năng trợ giúp cho những người này được khuyến nghị vì đối số trả trước là tĩnh và không thay đổi với mỗi cuộc gọi

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]]

Đây là một trường hợp rất hời hợt nhưng tốt hơn là an toàn hơn xin lỗi


2

Làm thế nào về điều này .. đã sử dụng một chuỗi thay vì danh sách, nhưng điều tương tự .. chuỗi có thể được coi như một danh sách trong Python:

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

Kết hợp từ 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))

Cảm ơn


2

Nếu không có itertools Python 3, bạn có thể làm một cái gì đó như thế này:

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

nơi ban đầu carry = "".


2

3 chức năng:

  1. tất cả sự kết hợp của danh sách n phần tử
  2. tất cả các kết hợp của danh sách n phần tử trong đó thứ tự không khác biệt
  3. tất cả hoán vị
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)

Tôi rất thích điều này!!! Cảm ơn bạn!!! Các hàm tổ hợp của Python hơi lạ một chút. Trong toán học, hàm "kết hợp" sẽ là Biến thể và "tổ hợp" Không thực sự là kết hợp. Tôi đoán rằng sẽ khiến mọi người nhầm lẫn đến với con trăn từ nhánh toán học, như nó đã làm với tôi lần này. Dù sao, một giải pháp tốt đẹp, cảm ơn rất nhiều!
Đumić Branislav

1

Đây là triển khai của tôi

    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
Việc thực hiện của bạn là gì giải quyết tốt hơn so với các triển khai trước đây được đăng ở đây.
dùng1767754

0

Bạn cũng có thể sử dụng chức năng powerset từ more_itertoolsgói tuyệt vời .

from more_itertools import powerset

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

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

Chúng tôi cũng có thể xác minh rằng nó đáp ứng yêu cầu của 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
Nếu tôi đúng, đây là mã chính xác được sao chép từ tài liệu python [ docs.python.org/3.6/l Library / itemools.html ]. Nếu vậy, xin vui lòng làm ref nguồn.
GabrielChu

cách tiếp cận thú vị
pelos

-1

Nếu ai đó đang tìm kiếm một danh sách đảo ngược, như tôi đã:

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')
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.