iki liste arasındaki kombinasyonlar?


187

Bir süredir başımı yapmaya çalıştığım bir algoritmanın etrafına sarmakta güçlük çekiyorum. Temel olarak, iki liste var ve iki listenin tüm kombinasyonlarını almak istiyorum.

Doğru açıklamıyor olabilirim, işte bir örnek.

name = 'a', 'b'
number = 1, 2

bu durumda çıktı:

1.  A1 B2
2.  B1 A2

Zor kısmı, "name" değişkeninde "number" değişkenindeki öğelerden daha fazla öğe olabileceğidir (sayı her zaman name değişkenine eşit veya bundan küçük olacaktır).

Nasıl tüm kombinasyonlar (döngü için iç içe?) Yapmak ve daha fazla isimde sayı listesinde olduğundan daha fazla öğe olması durumunda adı değişkenindeki öğeleri kaydırmak için mantık karışık.

Ben en iyi programcı değilim ama eğer birisi bunu başarmak için mantığı / algoritmayı açıklamama yardımcı olabilirse bir şans verebilirim düşünüyorum. Bu yüzden döngüler için yuvalanmış durumda kaldım.

Güncelleme:

İşte 3 değişken ve 2 sayı içeren çıktı:

name = 'a', 'b', 'c'
number = 1, 2

çıktı:

1.  A1 B2
2.  B1 A2
3.  A1 C2
4.  C1 A2
5.  B1 C2
6.  C1 B2


1
@ dm03514 Bunu gördüm ve itertools kullanarak biraz benzer hedeflere örnekler buldum ama python'da prototip oluşturuyorum ama başka bir dilde son kodu yazacağım, bu yüzden başka bir şekilde boş olmayan herhangi bir araç kullanmak istemiyorum.
user1735075

1
İstediğiniz gerçekten mantıklı değil. İlk liste A, B, C ve ikincisi 1,2 içeriyorsa, hangi sonucu beklersiniz? Verdiğiniz örnekte bir harf ve her biri bir sayı olmak üzere 4 farklı sonuç varsa (A1, A2, B1, B2) veya her iki listenin de aynı boyutta olması gerekiyorsa yapılabilir.
interjay

1
Interjay'e katılıyorum. Lütfen sonucu eşit olmayan boyutta belirtin, aksi takdirde genel bir çözüm sağlamak mümkün değildir.
Ekim'de Bakuriu

Herkese merhaba, çıktıyı 3 isim ve 2 rakamla göstermek için cevabı güncelledim .. Bunu açıklamayı düşündüm, neden aşağı oy verdiğinden emin değilim.
user1735075

Yanıtlar:


93

Not : Bu cevap yukarıda sorulan spesifik soru içindir. Google'dan buradaysanız ve sadece Python'da Kartezyen bir ürün almanın bir yolunu arıyorsanız itertools.productveya aradığınız şey basit bir liste kavrayışı olabilir - diğer cevaplara bakın.


Farz edin len(list1) >= len(list2). Öyleyse ne acze görünen uzunluktaki tüm permütasyon almaktır len(list2)gelen list1ve list2 öğelerle onları maç. Python'da:

import itertools
list1=['a','b','c']
list2=[1,2]

[list(zip(x,list2)) for x in itertools.permutations(list1,len(list2))]

İadeler

[[('a', 1), ('b', 2)], [('a', 1), ('c', 2)], [('b', 1), ('a', 2)], [('b', 1), ('c', 2)], [('c', 1), ('a', 2)], [('c', 1), ('b', 2)]]

1
Sonuç tam olarak istediğim şey, ama nasıl yapılacağının ardındaki mantığı paylaşmak mümkün mü? Kodumu C veya Java'ya dönüştürürsem, zip veya itertools'a erişimim olmaz (hayatı çok kolay hale getirmelerine rağmen)
user1735075 17:12

3
@ user1735075 Belgelere
tembellik

1
@ user1735075: python'un açık kaynak olduğunu biliyor musunuz? Böylece kaynakları indirebilir ve ne yaptığını görebilirsiniz. Dokümantasyonun aslında kullanmayan zipve benzeri bir örnek uygulaması olduğunu belirttiği için Bay Steak'e +1 .
Bakuriu

2
i kelimenin tam anlamıyla bile, bu örnek ile çalışmak için alamıyorum ... tüm ben zip nesnenin bir listesi ..: |
m1nkeh

1
@logic, kabul edilen çözümün ne olması gerektiğini sağlar.
Bernhard Wagner

502

En basit yol kullanmaktır itertools.product:

a = ["foo", "melon"]
b = [True, False]
c = list(itertools.product(a, b))
>> [("foo", True), ("foo", False), ("melon", True), ("melon", False)]

11
OP Kartezyen bir ürün istemiyordu ve bu cevap (diğerlerinin çoğunun yanı sıra) soruda belirtilen beklenen sonucu vermiyor.
interjay

17
@interjay çok haklısın, ancak çok fazla insan bu yanıtı doğru buluyor gibi görünse de, sadece sorunun başlığının bağlamdan yoksun olduğunu varsayabilirim.
xpy

3
@xpy Başlık her şeyi açıklamak için çok kısa. Bu yüzden asıl soruyu okumanız gerekiyor.
interjay

10
OP permütasyonlar istedi, ancak Google bu cevaba (benim gibi) kombinasyon arayan herkesi gönderdi - 8 kez oy aldığını görmekten memnunum!
Josh Friedlander

160

Yukarıdaki en basit olandan daha basit olabilir:

>>> a = ["foo", "bar"]
>>> b = [1, 2, 3]
>>> [(x,y) for x in a for y in b]  # for a list
[('foo', 1), ('foo', 2), ('foo', 3), ('bar', 1), ('bar', 2), ('bar', 3)]
>>> ((x,y) for x in a for y in b)  # for a generator if you worry about memory or time complexity.
<generator object <genexpr> at 0x1048de850>

herhangi bir ithalat olmadan


En iyi çözüm! Teşekkür ederim! Diğer çözümler ya yanlıştır ya da sadece> b vb. Gibi belirli durumlarda çalışır
Philipp Schwarz

3
En Pythonic çözümü! (ve gereksiz ithalatı önler)
Dalker

6
Zaman karmaşıklığı O (n ^ 2)
Deepak Sharma

2
Bahis çözümü !! Bare basics is the best way always
Sabyasachi

22

Bu işlev olarak sağlanan sadece benzersiz kombinasyonlarla kendisiyle çarpılan bir liste arıyordum.

import itertools
itertools.combinations(list, n_times)

İşte bir alıntı olarak Python belgelerinden olarak itertools O aradığınızı bulmanıza yardımcı olabilir.

Combinatoric generators:

Iterator                                 | Results
-----------------------------------------+----------------------------------------
product(p, q, ... [repeat=1])            | cartesian product, equivalent to a 
                                         |   nested for-loop
-----------------------------------------+----------------------------------------
permutations(p[, r])                     | r-length tuples, all possible 
                                         |   orderings, no repeated elements
-----------------------------------------+----------------------------------------
combinations(p, r)                       | r-length tuples, in sorted order, no 
                                         |   repeated elements
-----------------------------------------+----------------------------------------
combinations_with_replacement(p, r)      | r-length tuples, in sorted order, 
                                         | with repeated elements
-----------------------------------------+----------------------------------------
product('ABCD', repeat=2)                | AA AB AC AD BA BB BC BD CA CB CC CD DA DB DC DD
permutations('ABCD', 2)                  | AB AC AD BA BC BD CA CB CD DA DB DC
combinations('ABCD', 2)                  | AB AC AD BC BD CD
combinations_with_replacement('ABCD', 2) | AA AB AC AD BB BC BD CC CD DD

11

Bir satırlık liste kavrayışı denemek isteyebilirsiniz:

>>> [name+number for name in 'ab' for number in '12']
['a1', 'a2', 'b1', 'b2']
>>> [name+number for name in 'abc' for number in '12']
['a1', 'a2', 'b1', 'b2', 'c1', 'c2']

11

çok sayıda liste için tüm kombinasyonları bulmanın en iyi yolu:

import itertools
from pprint import pprint

inputdata = [
    ['a', 'b', 'c'],
    ['d'],
    ['e', 'f'],
]
result = list(itertools.product(*inputdata))
pprint(result)

sonuç:

[('a', 'd', 'e'),
 ('a', 'd', 'f'),
 ('b', 'd', 'e'),
 ('b', 'd', 'f'),
 ('c', 'd', 'e'),
 ('c', 'd', 'f')]

Teşekkürler, harika cevap!
toinbis

10

Veya kısa listeler için KISS cevabı:

[(i, j) for i in list1 for j in list2]

Itertools kadar performans değil ama python kullanıyorsunuz, bu yüzden performans zaten en büyük endişeniz değil ...

Diğer cevapları da seviyorum!


8

sonucu düzleştirmek için interjay'den gelen cevap için küçük bir gelişme.

>>> list3 = [zip(x,list2) for x in itertools.permutations(list1,len(list2))]
>>> import itertools
>>> chain = itertools.chain(*list3)
>>> list4 = list(chain)
[('a', 1), ('b', 2), ('a', 1), ('c', 2), ('b', 1), ('a', 2), ('b', 1), ('c', 2), ('c', 1), ('a', 2), ('c', 1), ('b', 2)]

bu linkten referans


4

İtertools olmadan

[(list1[i], list2[j]) for i in xrange(len(list1)) for j in xrange(len(list2))]

4

"İki liste verildiğinde, her listeden bir öğenin çiftlerinin olası tüm permütasyonlarını bulun" sorusunu yanıtlamak ve temel Python işlevlerini (yani, yineleme araçları olmadan) kullanmak ve böylece diğer programlama dilleri için çoğaltmayı kolaylaştırmak:

def rec(a, b, ll, size):
    ret = []
    for i,e in enumerate(a):
        for j,f in enumerate(b):
            l = [e+f]
            new_l = rec(a[i+1:], b[:j]+b[j+1:], ll, size)
            if not new_l:
                ret.append(l)
            for k in new_l:
                l_k = l + k
                ret.append(l_k)
                if len(l_k) == size:
                    ll.append(l_k)
    return ret

a = ['a','b','c']
b = ['1','2']
ll = []
rec(a,b,ll, min(len(a),len(b)))
print(ll)

İadeler

[['a1', 'b2'], ['a1', 'c2'], ['a2', 'b1'], ['a2', 'c1'], ['b1', 'c2'], ['b2', 'c1']]

2

Buna daha iyi yanıtlar sadece sağlanan belirli uzunluktaki listelerde işe yarar.

İşte herhangi bir giriş uzunluğu için çalışan bir sürüm. Ayrıca algoritmayı, kombinasyon ve permütasyonun matematiksel kavramları açısından netleştirir.

from itertools import combinations, permutations
list1 = ['1', '2']
list2 = ['A', 'B', 'C']

num_elements = min(len(list1), len(list2))
list1_combs = list(combinations(list1, num_elements))
list2_perms = list(permutations(list2, num_elements))
result = [
  tuple(zip(perm, comb))
  for comb in list1_combs
  for perm in list2_perms
]

for idx, ((l11, l12), (l21, l22)) in enumerate(result):
  print(f'{idx}: {l11}{l12} {l21}{l22}')

Bu çıktılar:

0: A1 B2
1: A1 C2
2: B1 A2
3: B1 C2
4: C1 A2
5: C1 B2
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.