Operasi pada setiap pasangan elemen dalam daftar

95

Menggunakan Python, saya ingin membandingkan setiap pasangan yang mungkin dalam sebuah daftar.

Misalkan saya punya

my_list = [1,2,3,4]

Saya ingin melakukan operasi (sebut saja foo) pada setiap kombinasi 2 elemen dari daftar.

Hasil akhirnya harus sama dengan

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

Pikiran pertama saya adalah mengulang dua kali melalui daftar secara manual, tetapi itu sepertinya tidak terlalu pythonic.

GuiSim
sumber

Jawaban:

231

Lihat product()di itertoolsmodul. Itu persis seperti yang Anda gambarkan.

import itertools

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

Ini sama dengan:

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

Sunting: Ada dua fungsi yang sangat mirip juga, permutations()dan combinations(). Untuk mengilustrasikan perbedaannya:

product() menghasilkan setiap kemungkinan pasangan elemen, termasuk semua duplikat:

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()menghasilkan semua urutan unik dari setiap pasangan elemen unik, menghilangkan x,xduplikat:

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

Terakhir, combinations()hanya menghasilkan setiap pasangan elemen unik, dalam urutan leksikografik:

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

Ketiga fungsi ini diperkenalkan di Python 2.6.

Ben Blank
sumber
1
Aneh, ketika saya menjalankan itertools.product (my_list, 2), ia mengeluh bahwa int tidak dapat dipanggil. Berfungsi setelah saya mengubahnya menjadi: itertools.product (my_list, repeat = 2)
ojrac
Perhatikan bahwa itertools.product () baru di Python 2.6.
Mike Mazur
Hanya untuk anak cucu, saya akan menunjukkan bahwa itertools.combinations tidak akan menghasilkan baris foo (1,1) atau foo (4,4) dalam contoh aslinya.
Kylotan
2
Juga ada Combination_with_replacement (). Seperti kombinasi (), tetapi termasuk diagonal (sesuai dengan ilustrasi).
Ziegl
1
Untuk yang malas: Untuk mendapatkan hasil di atas dengan permutations()dan combinations()digunakan r=2sebagai pengganti repeat=2digunakan pada contoh untukproduct()
Rob
15

Saya memiliki masalah serupa dan menemukan solusinya di sini . Ia bekerja tanpa harus mengimpor modul apa pun.

Misalkan daftar seperti:

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

Solusi satu baris yang disederhanakan akan terlihat seperti ini.

Semua kemungkinan pasangan , termasuk duplikat:

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

Semua kemungkinan pasangan, tidak termasuk duplikat :

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

Pasangan unik , yang urutannya tidak relevan:

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

Jika Anda tidak ingin mengoperasikan tetapi hanya untuk mendapatkan pasangan, menghapus fungsi foodan hanya menggunakan tupel sudah cukup.

Semua kemungkinan pasangan , termasuk duplikat:

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

Hasil:

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

Semua kemungkinan pasangan, tidak termasuk duplikat :

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

Hasil:

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

Pasangan unik , yang urutannya tidak relevan:

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

Hasil:

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

Sunting: Setelah pengerjaan ulang untuk menyederhanakan solusi ini, saya menyadari itu adalah pendekatan yang sama dari Adam Rosenfield. Saya harap penjelasan yang lebih besar membantu beberapa orang untuk memahaminya dengan lebih baik.

J0ANMM
sumber
2
Saya lebih suka ini daripada mengimpor perpustakaan, jauh lebih bersih!
sudo-nim
itertools adalah bagian dari Python. Ini bukan perpustakaan eksternal.
GuiSim
2

Jika Anda hanya memanggil suatu fungsi, Anda tidak dapat melakukan lebih baik dari:

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

Jika Anda ingin mengumpulkan daftar hasil pemanggilan fungsi, Anda dapat melakukan:

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

yang akan mengembalikan Anda daftar hasil penerapan foo(i, j)untuk setiap pasangan yang memungkinkan (i, j).

Adam Rosenfield
sumber
0
my_list = [1,2,3,4]

pairs=[[x,y] for x in my_list for y in my_list]
print (pairs)
karan dave
sumber
Meskipun kode ini mungkin memecahkan masalah, jawaban yang baik juga memerlukan penjelasan tentang apa kode tidak dan bagaimana memecahkan masalah.
BDL