Thao tác trên mọi cặp phần tử trong danh sách


94

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

Giả sử tôi có

my_list = [1,2,3,4]

Tôi muốn thực hiện một phép toán (hãy gọi nó là foo) trên mọi sự kết hợp của 2 phần tử từ danh sách.

Kết quả cuối cùng phải 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 lại hai lần danh sách theo cách thủ công, nhưng điều đó có vẻ không phức tạp lắm.

Câu trả lời:


229

Kiểm tra product()trong itertoolsmô-đun. 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)

Điều 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)

Chỉnh sửa: Có hai chức năng rất giống nhau, permutations()combinations(). Để minh họa chúng khác nhau như thế nào:

product() tạo mọi cặp phần tử có thể có, 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 tất cả các cấu trúc duy nhất của từng cặp phần tử duy nhất, loại bỏ các phần tử x,xtrùng lặp:

 .   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 từng cặp phần tử duy nhất, theo thứ tự từ vựng:

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

Cả ba hàm này đều được giới thiệu trong Python 2.6.


1
Thật kỳ lạ, khi tôi chạy itertools.product (my_list, 2), nó phàn nàn rằng int không thể gọi được. Công trình khi tôi thay đổi nó thành: itertools.product (my_list, lặp lại = 2)
ojrac

Lưu ý rằng itertools.product () mới trong Python 2.6.
Mike Mazur

Chỉ dành cho hậu thế, tôi sẽ chỉ ra rằng itertools.combaries sẽ không tạo ra các dòng foo (1,1) hoặc foo (4,4) trong ví dụ ban đầu.
Kylotan

2
Ngoài ra, còn có links_with_replacement (). Giống như các tổ hợp (), nhưng bao gồm cả đường chéo (phù hợp với các hình minh họa).
Ziegl

1
Dành cho kẻ lười biếng: Để có kết quả ở trên permutations(), hãy combinations()sử dụng r=2thay cho repeat=2ví dụ được sử dụng trong ví dụproduct()
Rob

15

Tôi đã gặp vấn đề tương tự và tìm thấy giải pháp ở đây . 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"]

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ể có , bao gồm cả các cặp trùng lặp:

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

Tất cả các cặp có thể có, không bao gồm các cặp trùng lặp :

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

Các cặp duy nhất , trong đó thứ tự không liên quan:

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 mà chỉ để lấy các cặp, loại bỏ chức năng foovà chỉ sử dụng một tuple là đủ.

Tất cả các cặp có thể có , bao gồm cả các cặp trùng lặp:

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ể có, không bao gồm các cặp trùng lặp :

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ác cặp duy nhất , trong đó thứ tự không liên quan:

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

Chỉnh sửa: Sau khi làm lại để đơn giản hóa giải pháp này, tôi nhận ra rằng nó có cùng cách tiếp cận với 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 rõ hơn.


2
Tôi thực sự thích điều này hơn là nhập thư viện, gọn gàng hơn nhiều!
sudo-nim

itertools là một phần của Python. Nó không phải là một thư viện bên ngoài.
GuiSim

2

Nếu bạn chỉ gọi một hàm, bạn thực sự không thể 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ả của việc gọi hàm, bạn có thể thực hiện:

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

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


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

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

Mặc dù mã này có thể giải quyết được vấn đề, một câu trả lời tốt cũng yêu cầu một lời giải thích của những gì mã lệnh thực hiện và cách nó giải quyết vấn đề.
BDL
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.