2009-06-03 43 views
50

Sử dụng Python, tôi muốn so sánh mọi cặp có thể trong một danh sách.Thao tác trên mỗi cặp phần tử trong danh sách

Giả sử tôi có

my_list = [1,2,3,4] 

tôi muốn làm phẫu thuật (chúng ta hãy gọi nó foo) trên tất cả các kết hợp của 2 yếu tố từ danh sách.

Kết quả cuối cùng sẽ được giống như

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

Suy nghĩ đầu tiên của tôi là để lặp hai lần thông qua danh sách một cách thủ công, nhưng điều đó dường như không phải là rất pythonic.

Trả lời

141

Khám phá product() trong mô-đun itertools. Nó thực hiện chính xác những gì bạn mô tả.

import itertools 

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

này tương đương với:

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

Edit: Có hai chức năng rất giống nhau là tốt, permutations()combinations(). Để minh họa cách chúng khác nhau:

product() tạo ra mỗi cặp có thể có của các yếu tố, bao gồm tất cả các bản sao:

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() tạo ra tất cả orderings độc đáo của mỗi cặp độc đáo của các yếu tố, loại bỏ sự x,x bản sao:

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

Cuối cùng, combinations() chỉ tạo mỗi cặp yếu tố duy nhất, theo thứ tự từ điển:

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

Cả ba chức năng này đều được giới thiệu trong Python 2.6.

+1

Không biết về itertools, điều này là hoàn hảo. Cảm ơn ! – GuiSim

+1

Odd, khi tôi chạy itertools.product (my_list, 2), nó phàn nàn rằng int không thể gọi được. Hoạt động khi tôi thay đổi nó thành: itertools.product (my_list, repeat = 2) – ojrac

+0

(sử dụng Python 2.6.2) – ojrac

2

Nếu bạn chỉ cần gọi một hàm, bạn có thể không thực sự làm tốt hơn nhiều so với:

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

Nếu bạn muốn thu thập một danh sách các kết quả gọi hàm, bạn có thể làm:

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

sẽ trả về danh sách kết quả của việc áp dụng foo(i, j) cho mỗi cặp có thể (i, j).

5

Tôi gặp sự cố tương tự và tìm thấy giải pháp here. Nó hoạt động mà không cần phải nhập bất kỳ mô-đun nào.

Giả sử một danh sách như:

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

Một giải pháp một dòng đơn giản sẽ trông như thế này.

Tất cả các cặp có thể, bao gồm bản sao:

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

Tất cả các cặp có thể, trừ bản sao:

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

cặp Unique, nơi trật tự là không thích hợp:

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

Trong trường hợp bạn không muốn hoạt động nhưng chỉ để nhận các cặp, hãy xóa hàm foo và chỉ sử dụng một bộ túp là đủ.

Tất cả các cặp có thể, bao gồm bản sao:

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

Kết quả:

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

Tất cả các cặp có thể, trừ bản sao:

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

Kết quả:

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

cặp Unique, nơi trật tự là không thích hợp:

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

Kết quả:

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

Edit: Sau khi làm lại để đơn giản hóa giải pháp này, tôi nhận ra nó là như nhau cách tiếp cận hơn Adam Rosenfield. Tôi hy vọng lời giải thích lớn hơn sẽ giúp một số người hiểu nó tốt hơn.

+1

Tôi rất thích điều này để nhập một thư viện, sạch hơn nhiều! –

Các vấn đề liên quan