Semua kombinasi daftar daftar

240

Saya pada dasarnya mencari versi python Combination ofList<List<int>>

Diberikan daftar daftar, saya membutuhkan daftar baru yang memberikan semua kemungkinan kombinasi item di antara daftar.

[[1,2,3],[4,5,6],[7,8,9,10]] -> [[1,4,7],[1,4,8],...,[3,6,10]]

Jumlah daftar tidak diketahui, jadi saya perlu sesuatu yang berfungsi untuk semua kasus. Poin bonus untuk keanggunan!

Lin
sumber

Jawaban:

428

Anda membutuhkan itertools.product:

>>> import itertools
>>> a = [[1,2,3],[4,5,6],[7,8,9,10]]
>>> list(itertools.product(*a))
[(1, 4, 7), (1, 4, 8), (1, 4, 9), (1, 4, 10), (1, 5, 7), (1, 5, 8), (1, 5, 9), (1, 5, 10), (1, 6, 7), (1, 6, 8), (1, 6, 9), (1, 6, 10), (2, 4, 7), (2, 4, 8), (2, 4, 9), (2, 4, 10), (2, 5, 7), (2, 5, 8), (2, 5, 9), (2, 5, 10), (2, 6, 7), (2, 6, 8), (2, 6, 9), (2, 6, 10), (3, 4, 7), (3, 4, 8), (3, 4, 9), (3, 4, 10), (3, 5, 7), (3, 5, 8), (3, 5, 9), (3, 5, 10), (3, 6, 7), (3, 6, 8), (3, 6, 9), (3, 6, 10)]
SilentGhost
sumber
20
Bisakah seseorang menjelaskan arti tanda bintang *a?
Serrano
52
*aberarti ini adalah argumen yang diteruskan ke fungsi atau metode. def fn(a,b,c):akan menanggapi fn(*[1,2,3]) referensi
mjallday
1
@mjallday, mungkinkah menambahkan juga kombinasi ini: (7,4,1), (8,4,1), (9,4,1), (10,4,1), (7,5, 1), (8,5,1), (9,5,1), (10,5,1) dll?
Reman
1
@Reman Tidak sepenuhnya jelas apa yang ingin Anda dapatkan tetapi jika itu, misalnya, juga kebalikan dari masing-masing tuple, Anda dapat menggunakan fungsi pembungkus yang mengambil asebagai input, beralih dari itertools.product(*a)dan yieldke tuple yang diproduksi oleh itertoolsdan versi terbalik ( misalnya membuat daftar, reverse()dan mengubahnya kembali ke tuple). Terbaik ajukan pertanyaan baru.
Joachim Wagner
24

Solusi paling elegan adalah dengan menggunakan itertools.product di python 2.6.

Jika Anda tidak menggunakan Python 2.6, dokumen untuk itertools.product sebenarnya menunjukkan fungsi yang setara untuk melakukan produk dengan cara "manual":

def product(*args, **kwds):
    # product('ABCD', 'xy') --> Ax Ay Bx By Cx Cy Dx Dy
    # product(range(2), repeat=3) --> 000 001 010 011 100 101 110 111
    pools = map(tuple, args) * kwds.get('repeat', 1)
    result = [[]]
    for pool in pools:
        result = [x+[y] for x in result for y in pool]
    for prod in result:
        yield tuple(prod)
Jarret Hardie
sumber
19
listOLists = [[1,2,3],[4,5,6],[7,8,9,10]]
for list in itertools.product(*listOLists):
  print list;

Saya harap Anda menemukan itu seanggun yang saya lakukan ketika saya pertama kali menemukannya.

Matthew Flaschen
sumber
5
Ada apa dengan titik koma itu? :)
Paolo Bergantino
3
Kekuatan kebiasaan. Saya suka bagaimana Python memungkinkan Anda menempatkan satu semi-colon, hanya untuk membantu kami programmer C / Java. Tapi jelas; sebenarnya bukan terminator pernyataan ketika Anda melakukan sesuatu seperti cetak ("foo") ;; yang sangat legal di C atau Java (meskipun tidak ada gunanya) tetapi dilarang dengan Python.
Matthew Flaschen
5

Numpy dapat melakukannya:

 >>> import numpy
 >>> a = [[1,2,3],[4,5,6],[7,8,9,10]]
 >>> [list(x) for x in numpy.array(numpy.meshgrid(*a)).T.reshape(-1,len(a))]
[[ 1, 4, 7], [1, 5, 7], [1, 6, 7], ....]
Diamantatos Paraskevas
sumber
Bisakah seseorang menjelaskan ini?
ashishv
5

Tidak ada yang salah dengan rekursi langsung untuk tugas ini, dan jika Anda membutuhkan versi yang dapat digunakan dengan string, ini mungkin sesuai dengan kebutuhan Anda:

combinations = []

def combine(terms, accum):
    last = (len(terms) == 1)
    n = len(terms[0])
    for i in range(n):
        item = accum + terms[0][i]
        if last:
            combinations.append(item)
        else:
            combine(terms[1:], item)


>>> a = [['ab','cd','ef'],['12','34','56']]
>>> combine(a, '')
>>> print(combinations)
['ab12', 'ab34', 'ab56', 'cd12', 'cd34', 'cd56', 'ef12', 'ef34', 'ef56']
duanev
sumber
3

Satu dapat menggunakan python dasar untuk ini. Kode membutuhkan fungsi untuk meratakan daftar daftar:

def flatten(B):    # function needed for code below;
    A = []
    for i in B:
        if type(i) == list: A.extend(i)
        else: A.append(i)
    return A

Maka seseorang dapat menjalankan:

L = [[1,2,3],[4,5,6],[7,8,9,10]]

outlist =[]; templist =[[]]
for sublist in L:
    outlist = templist; templist = [[]]
    for sitem in sublist:
        for oitem in outlist:
            newitem = [oitem]
            if newitem == [[]]: newitem = [sitem]
            else: newitem = [newitem[0], sitem]
            templist.append(flatten(newitem))

outlist = list(filter(lambda x: len(x)==len(L), templist))  # remove some partial lists that also creep in;
print(outlist)

Keluaran:

[[1, 4, 7], [2, 4, 7], [3, 4, 7], 
[1, 5, 7], [2, 5, 7], [3, 5, 7], 
[1, 6, 7], [2, 6, 7], [3, 6, 7], 
[1, 4, 8], [2, 4, 8], [3, 4, 8], 
[1, 5, 8], [2, 5, 8], [3, 5, 8], 
[1, 6, 8], [2, 6, 8], [3, 6, 8], 
[1, 4, 9], [2, 4, 9], [3, 4, 9], 
[1, 5, 9], [2, 5, 9], [3, 5, 9], 
[1, 6, 9], [2, 6, 9], [3, 6, 9], 
[1, 4, 10], [2, 4, 10], [3, 4, 10], 
[1, 5, 10], [2, 5, 10], [3, 5, 10], 
[1, 6, 10], [2, 6, 10], [3, 6, 10]]
juga
sumber
-1
from itertools import product 
list_vals = [['Brand Acronym:CBIQ', 'Brand Acronym :KMEFIC'],['Brand Country:DXB','Brand Country:BH']]
list(product(*list_vals))

Keluaran:

[('Akronim Merek: CBIQ', 'Merek Negara: DXB'),
('Akronim Merek: CBIQ', 'Merek Negara: BH'),
('Akronim Merek: KMEFIC', 'Merek Negara: DXB'),
( 'Merek Akronim: KMEFIC', 'Negara Merek: BH')]

Kez
sumber
Jawaban ini harus diterima, karena itu satu-satunya yang menggunakan fungsi bawaan, sambil menyoroti bahwa itu juga berfungsi untuk semua jenis heterogen.
pedjjj
Bagaimana jawaban ini berbeda dari yang diberikan bertahun-tahun yang lalu?
Dawid Laszuk