การดำเนินการกับทุกคู่ขององค์ประกอบในรายการ


106

เมื่อใช้ Python ฉันต้องการเปรียบเทียบทุกคู่ที่เป็นไปได้ในรายการ

สมมติว่าฉันมี

my_list = [1,2,3,4]

ฉันต้องการดำเนินการ (ขอเรียกว่า foo) ในทุก ๆ 2 องค์ประกอบจากรายการ

ผลลัพธ์สุดท้ายควรจะเหมือนกับ

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

ความคิดแรกของฉันคือการทำซ้ำสองครั้งผ่านรายการด้วยตนเอง แต่ดูเหมือนจะไม่มากนัก

คำตอบ:


247

ตรวจสอบproduct()ในitertoolsโมดูล ไม่ตรงตามที่คุณอธิบาย

import itertools

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

เทียบเท่ากับ:

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

แก้ไข:มีสองฟังก์ชั่นที่คล้ายกันมากเช่นกันและpermutations() combinations()เพื่อแสดงให้เห็นว่าแตกต่างกันอย่างไร:

product() สร้างการจับคู่องค์ประกอบที่เป็นไปได้ทั้งหมดรวมถึงรายการที่ซ้ำกันทั้งหมด:

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()สร้างลำดับที่ไม่ซ้ำกันทั้งหมดของแต่ละคู่ขององค์ประกอบที่ไม่x,xซ้ำกันกำจัดรายการที่ซ้ำกัน:

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

สุดท้ายcombinations()สร้างเฉพาะแต่ละคู่ขององค์ประกอบที่ไม่ซ้ำกันตามลำดับศัพท์:

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

ทั้งสามฟังก์ชั่นเหล่านี้ถูกนำมาใช้ใน Python 2.6


1
แปลกเมื่อฉันเรียกใช้ itertools.product (my_list, 2) มันบ่นว่า int ไม่สามารถโทรได้ ใช้งานได้เมื่อฉันเปลี่ยนเป็น: itertools.product (my_list, repeat = 2)
ojrac

โปรดทราบว่า itertools.product () เป็นของใหม่ใน Python 2.6
Mike Mazur

สำหรับคนรุ่นหลังฉันจะชี้ให้เห็นว่า itertools.combinations จะไม่สร้างบรรทัด foo (1,1) หรือ foo (4,4) ในตัวอย่างดั้งเดิม
Kylotan

3
นอกจากนี้ยังมี combinations_with_replacement () เช่นเดียวกับชุดค่าผสม () แต่รวมถึงเส้นทแยงมุมด้วย (สอดคล้องกับภาพประกอบ)
Ziegl

1
สำหรับคนขี้เกียจ: เพื่อให้ได้ผลลัพธ์ข้างต้นpermutations()และcombinations()ใช้r=2แทนการrepeat=2ใช้ในตัวอย่างสำหรับproduct()
Rob

16

ผมมีปัญหาที่คล้ายกันและพบว่าการแก้ปัญหาที่นี่ ใช้งานได้โดยไม่ต้องนำเข้าโมดูลใด ๆ

สมมติว่ารายการเช่น:

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

โซลูชันบรรทัดเดียวที่เรียบง่ายจะมีลักษณะเช่นนี้

คู่ที่เป็นไปได้ทั้งหมดรวมถึงรายการที่ซ้ำกัน:

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

คู่ที่เป็นไปได้ทั้งหมดไม่รวมรายการที่ซ้ำกัน :

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

คู่ที่ไม่ซ้ำกันโดยที่คำสั่งไม่เกี่ยวข้อง:

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

ในกรณีที่คุณไม่ต้องการใช้งาน แต่เพียงเพื่อให้ได้คู่การลบฟังก์ชันfooและใช้เพียงทูเปิลก็เพียงพอแล้ว

คู่ที่เป็นไปได้ทั้งหมดรวมถึงรายการที่ซ้ำกัน:

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

ผลลัพธ์:

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

คู่ที่เป็นไปได้ทั้งหมดไม่รวมรายการที่ซ้ำกัน :

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

ผลลัพธ์:

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

คู่ที่ไม่ซ้ำกันโดยที่คำสั่งไม่เกี่ยวข้อง:

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

ผลลัพธ์:

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

แก้ไข: หลังจากการทำซ้ำเพื่อลดความซับซ้อนของโซลูชันนี้ฉันรู้ว่ามันเป็นแนวทางเดียวกันกับ Adam Rosenfield ฉันหวังว่าคำอธิบายที่กว้างขึ้นจะช่วยให้บางคนเข้าใจได้ดีขึ้น


2
ฉันชอบสิ่งนี้มากในการนำเข้าห้องสมุดสะอาดกว่ามาก!
sudo-nim

1
itertools เป็นส่วนหนึ่งของ Python ไม่ใช่ห้องสมุดภายนอก
GuiSim

3

หากคุณแค่เรียกใช้ฟังก์ชันคุณไม่สามารถทำได้ดีไปกว่า:

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

หากคุณต้องการรวบรวมรายการผลลัพธ์ของการเรียกใช้ฟังก์ชันคุณสามารถทำได้:

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

ซึ่งจะนำคุณกลับรายการผลของการใช้ที่แต่ละคู่ที่เป็นไปได้foo(i, j)(i, j)


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

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

แม้ว่ารหัสนี้อาจจะแก้ปัญหาได้คำตอบที่ดียังต้องมีคำอธิบายของสิ่งที่รหัสไม่และวิธีการที่จะแก้ปัญหาที่เกิดขึ้น
BDL
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.