Bir listedeki her öğe çifti üzerinde işlem


106

Python kullanarak, bir listedeki olası her çifti karşılaştırmak istiyorum.

Varsayalım ki bende

my_list = [1,2,3,4]

Listedeki 2 öğenin her kombinasyonunda bir işlem yapmak istiyorum (buna foo diyelim).

Nihai sonuç aynı olmalıdır

foo(1,1)
foo(1,2)
...
foo(4,3)
foo(4,4)

İlk düşüncem listeyi manuel olarak iki kez yinelemekti, ancak bu pek pitonik görünmüyor.

Yanıtlar:


247

Check product()in itertoolsmodülü. Tam olarak tarif ettiğiniz şeyi yapıyor.

import itertools

my_list = [1,2,3,4]
for pair in itertools.product(my_list, repeat=2):
    foo(*pair)

Bu şuna eşdeğerdir:

my_list = [1,2,3,4]
for x in my_list:
    for y in my_list:
        foo(x, y)

Düzenleme: Çok benzer iki işlev vardır permutations()ve combinations(). Nasıl farklı olduklarını göstermek için:

product() tüm kopyalar da dahil olmak üzere olası her öğe eşleşmesini oluşturur:

1,1  1,2  1,3  1,4
2,1  2,2  2,3  2,4
3,1  3,2  3,3  3,4
4,1  4,2  4,3  4,4

permutations()her bir benzersiz öğe çiftinin tüm benzersiz sıralamalarını üreterek x,xkopyaları ortadan kaldırır :

 .   1,2  1,3  1,4
2,1   .   2,3  2,4
3,1  3,2   .   3,4
4,1  4,2  4,3   .

Son olarak, combinations()yalnızca her bir benzersiz öğe çiftini sözlüksel sırayla üretir:

 .   1,2  1,3  1,4
 .    .   2,3  2,4
 .    .    .   3,4
 .    .    .    .

Bu işlevlerin üçü de Python 2.6'da tanıtıldı.


1
Garip, itertools.product (my_list, 2) çalıştırdığımda int çağrılabilir olmadığından şikayet ediyor. İtertools.product (my_list, tekrar = 2)
ojrac

İtertools.product () 'un Python 2.6'da yeni olduğunu unutmayın.
Mike Mazur

Gelecek nesiller için, itertools.combinations'ın orijinal örnekte foo (1,1) veya foo (4,4) satırlarını oluşturmayacağına işaret edeceğim.
Kylotan

3
Ayrıca ,_replacement () ile kombinasyonlar vardır. Kombinasyonlar gibi (), ancak köşegen dahil (resimlere uygun olarak).
Ziegl

1
Tembeller için: Yukarıdaki sonuçları örnekte kullanılan yerine kullanmak permutations()ve combinations()kullanmak içinr=2repeat=2product()
Rob

16

Benzer bir sorun yaşadım ve çözümü burada buldum . Herhangi bir modülü içe aktarmak zorunda kalmadan çalışır.

Şöyle bir liste varsayarsak:

people = ["Lisa","Pam","Phil","John"]

Basitleştirilmiş tek satırlık bir çözüm şuna benzer.

Yinelenenler dahil tüm olası çiftler :

result = [foo(p1, p2) for p1 in people for p2 in people]

Yinelenenler hariç tüm olası çiftler :

result = [foo(p1, p2) for p1 in people for p2 in people if p1 != p2]

Siparişin alakasız olduğu benzersiz çiftler :

result = [foo(people[p1], people[p2]) for p1 in range(len(people)) for p2 in range(p1+1,len(people))]

Çalıştırmak istemiyorsanız, sadece çiftleri elde etmek istiyorsanız, işlevi kaldırmak foove sadece bir tuple kullanmak yeterli olacaktır.

Yinelenenler dahil tüm olası çiftler :

list_of_pairs = [(p1, p2) for p1 in people for p2 in people]

Sonuç:

('Lisa', 'Lisa')
('Lisa', 'Pam')
('Lisa', 'Phil')
('Lisa', 'John')
('Pam', 'Lisa')
('Pam', 'Pam')
('Pam', 'Phil')
('Pam', 'John')
('Phil', 'Lisa')
('Phil', 'Pam')
('Phil', 'Phil')
('Phil', 'John')
('John', 'Lisa')
('John', 'Pam')
('John', 'Phil')
('John', 'John')

Yinelenenler hariç tüm olası çiftler :

list_of_pairs = [(p1, p2) for p1 in people for p2 in people if p1 != p2]

Sonuç:

('Lisa', 'Pam')
('Lisa', 'Phil')
('Lisa', 'John')
('Pam', 'Lisa')
('Pam', 'Phil')
('Pam', 'John')
('Phil', 'Lisa')
('Phil', 'Pam')
('Phil', 'John')
('John', 'Lisa')
('John', 'Pam')
('John', 'Phil')

Siparişin alakasız olduğu benzersiz çiftler :

list_of_pairs = [(people[p1], people[p2]) for p1 in range(len(people)) for p2 in range(p1+1,len(people))]

Sonuç:

('Lisa', 'Pam')
('Lisa', 'Phil')
('Lisa', 'John')
('Pam', 'Phil')
('Pam', 'John')
('Phil', 'John')

Düzenleme: Bu çözümü basitleştirmek için yeniden çalıştıktan sonra, Adam Rosenfield ile aynı yaklaşım olduğunu fark ettim. Umarım daha büyük açıklama bazılarının onu daha iyi anlamasına yardımcı olur.


2
Bunu bir kitaplığı içe aktarmaya tercih ediyorum, çok daha temiz!
sudo-nim

1
itertools, Python'un bir parçasıdır. Harici bir kitaplık değil.
GuiSim

3

Sadece bir işlevi arıyorsanız, gerçekten şunlardan daha iyisini yapamazsınız:

for i in my_list:
    for j in my_list:
        foo(i, j)

İşlevi çağırmanın sonuçlarının bir listesini toplamak istiyorsanız, şunları yapabilirsiniz:

[foo(i, j) for i in my_list for j in my_list]

bu size foo(i, j)olası her çifte başvurmanın sonucunun bir listesini verecektir (i, j).


0
my_list = [1,2,3,4]

pairs=[[x,y] for x in my_list for y in my_list]
print (pairs)

Bu kod sorunu çözse de, iyi bir yanıt , kodun ne yaptığına ve sorunu nasıl çözdüğüne dair bir açıklama gerektirir .
BDL
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.