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.

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.


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.


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


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

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

Meskipun kode ini mungkin memecahkan masalah, jawaban yang baik juga memerlukan penjelasan tentang apa kode tidak dan bagaimana memecahkan masalah.
BDL
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.