Bir liste öğelerinin tüm olası kombinasyonlarını nasıl elde edebilirim?


423

15 numara ile bir liste var ve ben bu sayıların 32.768 kombinasyonları üreten bazı kod yazmak gerekiyor.

Kod buldum görünüşe göre ben aradığım yapar (Googling tarafından), ama kod oldukça opak bulundu ve bunu kullanarak dikkatli değilim. Ayrıca daha şık bir çözüm olması gerektiğini hissediyorum.

Benim başıma gelen tek şey, 1–32768 ondalık sayıları arasında döngü yapmak ve bunları ikili sayıya dönüştürmek ve ikili sayıları uygun sayıları seçmek için bir filtre olarak kullanmak olacaktır.

Daha iyi bir yol bilen var mı? Kullanılması map()belki?


9
Okuyucular, liste öğelerinin benzersiz olup olmadığını son derece önemli bir husustur, çünkü birçok algoritma bazı alt kümeleri aşacaktır (örn. 'Abccc' -> ['', 'a', 'b', 'c', 'c' , 'c', 'ac', 'ac', 'ac', ...]. Kolay bir çözüm, permütasyonlarını almadan önce bir kümedeki tüm öğeleri
sürmektir

@ninjagecko Her biri en iyi O (n) olduğundan Set kitaplığını kullanmak etkili değildir. Böylece bir kümeye n fonksiyon eklemek aslında O (n ^ 2)!
Scott Biggs

Soruyu dikkatlice okurken, OP'nin tüm kombinasyonları değil, 15 sayı listesinin PowerSet'ini istediği anlaşılıyor . Bence cevaplar her yerde olabilir.
Scott Biggs

@Scott Biggs: Python'u burada aldığınızdan emin misiniz? Set eklemeleri ve aramalar O (1) ortalama büyüklüğündedir. Sözlük gibi. Karma kullanırlar. Python'un özel bir set kütüphanesi yoktur (standart kütüphanede bulunur). Buraya fonksiyonlar değil rakamlar ekliyoruz. (O (2 ^ n) belleği kullanmak hala verimsiz olacaktır; güç seti yerine kombinasyon isteyen insanlar için uygun çözüm basit bir özyinelemeli uygulamadır product, vb.)
ninjagecko

Yanıtlar:


467

İtertools.com'a bir göz atın :

itertools.combinations(iterable, r)

Tekrarlanabilir girişten elemanların r uzunluk sıralarını döndürün.

Kombinasyonlar sözlükbilimsel sıralama düzeninde yayılır. Bu nedenle, yinelenebilir girdi sıralanırsa, kombinasyon tupleri sıralı olarak üretilir.

2.6'dan beri piller dahildir!


31
hepsini listeleyebilirsiniz. list(itertools.combinations(iterable, r))
silgon

1
gerektirmeyen herhangi bir şey r, yani elemanların herhangi bir uzunluk alt dizisinin kombinasyonları.
mLstudent33

630

Bu cevap bir yönü kaçırdı: OP TÜM kombinasyonları istedi ... sadece "r" uzunluk kombinasyonlarını değil.

Yani ya tüm "L" uzunlukları arasında döngü yapmalısınız:

import itertools

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

Veya - şık olmak istiyorsanız (veya kodunuzu sizden sonra okuyanın beynini bükmek istiyorsanız) - "kombinasyonlar ()" jeneratörleri zincirini oluşturabilir ve bunu tekrarlayabilirsiniz:

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
Destek için teşekkürler! Yukarıdaki yanıtı yayınladığımdan sonraki haftalarda, Ben'in aradığı konseptin ADI'nın 15 öğeden oluşan orijinal kümenin "güç kümesi" olduğunu buldum. Aslında, standart python "itertools" doc sayfasında örnek bir uygulama verilmiştir: docs.python.org/library/itertools.html ("powerset" için grep).
Dan H

38
Şimdiye kadar okuyan herkes için: Belgelerinpowerset() tarifler bölümündeki jeneratör işlevi daha basittir, potansiyel olarak daha az bellek kullanır ve burada gösterilen uygulamadan daha hızlıdır. itertools
martineau

Tüm kombinasyonları sözlükbilimsel sırayla oluşturmak mümkün müdür?
guik

@guik: Verdiği itertools.combinationslistelerde öğe sırasını koruduğundan % 99 eminim . Böylece, girdi sözcüksel olarak sıralanırsa, çıktıların her biri de olacaktır.
Dan H

Evet, itertools.combinationsn arasında k kombinasyonlarını sözlük sırasına göre oluşturur, ancak n arasında k'ye kadar olan tüm kombinasyonları oluşturmaz . k'e kadarpowerset tüm kombinasyonları oluşturur , ancak anladığım kadarıyla sözlükbilimsel sırada değil: powerset ([1,2]) -> [(), (1,), (2,), (1, 2)] . Olmamalı mı: [(), (1,), (1, 2), (2,)]?
guik

52

İşte itertools kullanan tembel bir astar:

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

Bu cevabın arkasındaki ana fikir: 2 ^ N kombinasyonu vardır - N uzunluğundaki ikili dizelerin sayısı ile aynıdır. Her ikili dize için, "1" e karşılık gelen tüm öğeleri seçersiniz.

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

Düşünülmesi gereken şeyler:

  • Bu Arayabileceğin gerektirir len(...)üzerinde items(: eğer çözüm itemsbir jeneratör gibi bir iterable gibi bir şey, ilk bir liste haline getirmek items=list(_itemsArg))
  • Bu, yineleme sırasının itemsrastgele olmamasını gerektirir (geçici çözüm: deli olma)
  • Bu, öğelerin benzersiz veya başka şekilde olmasını {2,2,1}ve {2,1,1}her ikisinin de daralmasını gerektirir {2,1}(geçici çözüm: için collections.Counterbir yedek değiştirme olarak kullanın set; temelde bir çoklu ayardır ... ancak daha sonra tuple(sorted(Counter(...).elements()))yıkanabilir olması gerekiyorsa kullanmanız gerekebilir)

gösteri

>>> 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 tarafından son derece onaylanan cevap altındaki yorumlarda , Dan'ın kendisi de dahil olmak üzere dokümantasyondakipowerset() tariften bahsedilmektedir . Ancak , şimdiye kadar kimse bunu yanıt olarak göndermedi. Muhtemelen soruna en iyi yaklaşım olmasa da daha iyi olanlardan biri olduğu ve başka bir yorumcunun biraz cesaretlendirdiği için aşağıda gösterilmiştir. İşlev, mümkün olan her uzunluktaki liste öğelerinin tüm benzersiz kombinasyonlarını üretir (sıfır içerenler ve tüm öğeler dahil).itertools

Not :, ustaca farklı, amaç eşsiz elemanların sadece kombinasyonlarını elde etmek ise, hat değiştirmek s = list(iterable)için s = list(set(iterable))herhangi bir yinelenen unsurları ortadan kaldırmak. Ne olursa olsun, iterablenihayetinde listjeneratörlerle çalışacağı bir araca dönüşmesi (diğer cevapların çoğunun aksine).

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

Çıktı:

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()İlk etapta dönüşüm ne için?
AMC

@Alexander: Yinelemenin uzunluğunun belirlenmesine izin vermek için.
martineau

36

İşte özyineleme kullanan biri:

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

Bu, yazdırmak yerine bir liste listesi döndürmek için değiştirilebilir mi?
James Vickery

@JamesVickery evet, ya fonksiyonun dışında bir liste yapmaya ve buna ekleme yapabilir ya da (daha iyi) fonksiyonu bir jeneratör haline getirebilir, 'verim' anahtar kelimesine bakabilirsiniz :)
Dangercrow

new_data = copy.copy(data)- gördüğüm kadarıyla bu satır gereksiz, hiçbir şey üzerinde etkisi yok
Dmitriy Fialkovskiy

31

Bu tek satırlık size tüm kombinasyonları verir (arasına 0ve nürün orijinal liste / set içeriyorsa nfarklı unsurları) ve yerli yöntemini kullanıritertools.combinations :

Python 2

from itertools import combinations

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

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

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

Çıktı şöyle olacaktır:

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

Çevrimiçi deneyin:

http://ideone.com/COghfX


Bu bir permütasyon
AdHominem

15
@AdHominem: hayır, değil. Tüm kombinasyonların bir listesi. Permütasyonlar, örn ['b', 'a'].
naught101

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

@ 0x48piraj: fark ettiğiniz için teşekkür ederim, cevabımı düzenledim!
Mathieu Rodic

21

Dan H ile Ben'in tüm kombinasyonları istediğini kabul ediyorum . itertools.combinations()tüm kombinasyonları vermez.

Başka bir sorun, yinelenebilir girdi büyükse, listedeki her şey yerine bir jeneratör döndürmek daha iyidir:

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

1
Güzel bir örnek. Jeneratörleri seviyorum ... ve Python'u sahip oldukları için seviyorum! Bu örnek, bir seferde yalnızca bir combations () nesnesine sahiptir ve bir seferde kombinasyonlardan birini verir. (Belki de bunun yerine def bloğunu bir kullanım örneği olarak eklemek istersiniz.) Uygulamamın (yukarıda verilen zincir () ile) çok daha kötü olmadığını unutmayın: tüm len (yinelenebilir) jeneratörleri oluşturan bir kez ... ama 2 ** len (yinelenebilir) kombinasyonların tümünü bir kerede oluşturmaz, çünkü - benim anlayışımla - zincir sonraki jeneratörü çizmeden önce ilk jeneratörü "tüketir".
Dan H

18

Bu, özyinelemeyi destekleyen tüm programlama dillerine kolayca aktarılabilen bir yaklaşımdır ( yineleme yok, verim yok, liste kavrama yok) :

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! Güzel bir uygulama.Prolog'dan HEAD = a [0], TAIL = a [1:] tanıyorum. Veya araba = a [0], cdr = a [1:] Lisp. Burada memoizasyonu kullanabilir miyiz acaba ...
Javier Ruiz

Doğru. Liste dilimleme O (k) 'dir, burada k dilimin uzunluğudur. Sanırım biri bir haritada bir arama yaparak bunu hızlandırabilirdi ki bu, onu tüm çalışmalarda ilk (O) yapacaktır. Ancak bu uygulamaya performans için başvurulmaması gerektiğini unutmayın. Bunun için daha iyi uygulamalar var. Bu uygulama yalnızca diğer birçok dilde basitlik ve taşınabilirlik içindir.
Jonathan R

14

Bu basit kodu kullanarak python'da bir listenin tüm kombinasyonlarını oluşturabilirsiniz

import itertools

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

Sonuç:

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

Bu koddaki hata: boş kümeyi döndürmez. Xrange (0, ...) anlamına gelebilir, ancak test etmediniz. edit : Devam ettim ve cevabınızı düzeltmek için düzenledim.
ninjagecko

13

Bu işlevi itertools veya başka herhangi bir ek kitaplığı içe aktarmadan yanıt arayanlar için ekleyeceğimi düşündüm.

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

Basit Verim Jeneratörü Kullanımı:

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

Yukarıdaki Kullanım örneğinden çıktı:

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


Bence bu çok düzgün bir çözüm.
greentec

8

İşte itertools.combinationsfonksiyonun kullanılmasını içeren başka bir çözüm (tek astar), ancak burada bir çift liste kavrayışı kullanıyoruz (for döngüsü veya toplamının aksine):

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

Demo:

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

çıktı

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

4

Aşağıda, diğer benzer yanıta benzer bir "standart özyinelemeli yanıt" bulunmaktadır https://stackoverflow.com/a/23743696/711085 . (Tüm N! Permütasyonlarını işleyebilmemizin bir yolu olmadığından, gerçekçi olarak yığın boşluğunun bitmesi konusunda endişelenmemize gerek yoktur.)

Sırasıyla her öğeyi ziyaret eder ve onu alır veya bırakır (bu algoritmadan doğrudan 2 ^ N kardinalitesini görebiliriz).

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

Demo:

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

Liste kavrayışı kullanma:

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 )

Çıktı:

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

4
Bu teklif kümeler oluşturmak için dize mangling yapmaktır?!?! Kutsal karga .... Ve: güç setini döndürmüyor, daha çok combations_with_replacement () gibi bir şey döndürüyor. (Bkz. Docs.python.org/library/… )
Dan H

Bu gerçekten Combisation_with_replacement () ile aynı , ama en azından benim kutusunda bu itertools biraz daha hızlı çalışır . Ne diyebilirim ki, liste kavrayışlarını severim.
ZMK

1
Cevap için teşekkür ederim! Liste oluşturmaya ne dersiniz? ['A', 'A'], ['A', 'B'], ['A', 'C'], ['B', 'A'], [ 'B', 'B'], ['B', 'C'], ['C', 'A'], ['C', 'B'] ve ['C', 'C'] içeren her şey?
Karyo

Çok ilginç, ama pitonum buradaki incelikleri anlamaya yetmiyor. ListCombined'i farklı kapsamlarda kullanma konusunda özel bir şey var mı ve for döngüsünün hepsi tek bir satırda mı? Ben biraz şans ile Java bu port çalışıyorum.
Scott Biggs

2

Bu kod, iç içe listelerle basit bir algoritma kullanır ...

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

Bu kodun yaptığı şey döndürülecek. [ListOfCombinations, listOfCombinationsGroupedBySize]. Ne yazık ki demo girişi ile çalıştırıldığında 64 yerine 63 eleman verir; boş kümeyi (bu durumda boş dize "") eksik görünüyor .
ninjagecko

2

Tüm kombinasyonları elde etmek için itertools'u kullanmanın çok daha pratik olduğunu biliyorum , ancak bunu sadece arzu ederseniz, sadece kod anlama ile verdiğiniz takdirde, sadece liste kavrama ile elde edebilirsiniz. çok

İki çift kombinasyonu için:

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


Ve üç çiftin kombinasyonları için, bu kadar kolay:

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


Sonuç itertools.combinations ile aynıdır:

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

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

İşte iki uygulama itertools.combinations

Bir liste döndüren

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

Biri bir jeneratör döndürür

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

Başlatma argümanının statik olduğu ve her çağrıda değişmediği için bunlara yardımcı işlev sağlamanın tavsiye edildiğini lütfen unutmayın

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

Bu çok yüzeysel bir durum ama üzgün olmaktan daha iyi


2

Buna ne dersin .. liste yerine bir dize kullandı ama aynı şey .. string Python'da bir liste gibi ele alınabilir:

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'tan kombinasyon

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

Teşekkürler


2

itertoolsPython 3 olmadan böyle bir şey yapabilirsiniz:

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

başlangıçta nerede carry = "".


2

3 fonksiyon:

  1. n elemanlar listesinin tüm kombinasyonları
  2. n öğesinin tüm kombinasyonları, siparişin farklı olmadığı yerlerde listelenir
  3. tüm permütasyonlar
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)

Bunu çok seviyorum !!! Teşekkür ederim!!! Python'un kombinatorik fonksiyonları biraz garip. Matematikte "kombinasyonlar" işlevi Varyasyonlar ve "comboNoOrder" aslında kombinasyonlardır. Tahmin ediyorum ki, bu sefer bana olduğu gibi, matematik dalından python'a gelen insanlar karıştırıyor. Her neyse, güzel bir çözüm, çok teşekkürler!
Đumić Branislav

1

Bu benim uygulamam

    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
Uygulamanız, burada yayınlanan önceki uygulamalardan daha iyi çözülüyor.
user1767754

0

Güçmore_itertools paketi işlevini mükemmel paketten de kullanabilirsiniz .

from more_itertools import powerset

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

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

Ayrıca OP'nin gereksinimlerini karşıladığını da doğrulayabiliriz

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
Haklıysam , bu tam olarak python belgelerinden [ docs.python.org/3.6/library/itertools.html ] kopyalanan koddur . Eğer öyleyse, lütfen kaynağı ref yapın.
GabrielChu

ilginç bir yaklaşım
pelos

-1

Birisi benim gibi ters bir liste arıyor:

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')
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.