ฉันจะเปรียบเทียบรายการสองรายการในหลามและการจับคู่ส่งคืนได้อย่างไร


380

ฉันต้องการจดรายการสองรายการและค้นหาค่าที่ปรากฏในทั้งสองรายการ

a = [1, 2, 3, 4, 5]
b = [9, 8, 7, 6, 5]

returnMatches(a, b)

จะกลับมา[5]เช่น


4
คำตอบด้านล่างดูเหมือนจะผิดสำหรับฉัน จะเกิดอะไรขึ้นถ้ามีหมายเลขซ้ำในรายการใดรายการหนึ่งแน่นอนคุณต้องการที่จะรู้ว่า (?) (เช่นพูดว่ารายการทั้งสองมี '5' สองครั้ง) การแก้ปัญหาโดยใช้ชุดจะลบรายการที่ทำซ้ำทั้งหมดทันทีและคุณจะสูญเสีย ข้อมูลนั้น
MH

เป็นไปได้ที่ซ้ำกันของวิธีค้นหาจุดตัดรายการ
Kushan Gunasekera

คำตอบ:


486

ไม่ใช่วิธีที่มีประสิทธิภาพที่สุด แต่โดยวิธีที่ชัดเจนที่สุดคือ:

>>> a = [1, 2, 3, 4, 5]
>>> b = [9, 8, 7, 6, 5]
>>> set(a) & set(b)
{5}

ถ้าคำสั่งซื้อมีความสำคัญคุณสามารถทำได้ด้วยรายการความเข้าใจเช่นนี้

>>> [i for i, j in zip(a, b) if i == j]
[5]

(ใช้ได้กับรายการที่มีขนาดเท่ากันเท่านั้นซึ่งหมายถึงลำดับความสำคัญ)


15
ข้อควรระวังความเข้าใจในรายการไม่จำเป็นต้องเป็นตัวเลือกที่เร็วกว่า สำหรับชุดที่มีขนาดใหญ่กว่า (ซึ่งประสิทธิภาพมีความสำคัญมากที่สุด) การเปรียบเทียบระดับบิต ( &) หรือset(a).intersection(b)จะเร็วหรือเร็วกว่าความเข้าใจในรายการ
Joshmaker

24
ข้อควรระวังอีกข้อหนึ่ง: ความเข้าใจในรายการจะค้นหาค่าที่ปรากฏทั้งในตำแหน่ง SAME (นี่คือความหมาย SilentGhost โดย "คำสั่งมีความสำคัญ") โซลูชันการตั้งค่าการตัดกันจะพบการจับคู่ที่ตำแหน่งต่างกัน เหล่านี้เป็นคำตอบให้กับคำถาม 2 ข้อแตกต่างกันมาก ... (คำถามของสหกรณ์ไม่ชัดเจนเป็นไปได้ที่มันจะขอ)
drevicko

คุณจะทำอย่างไรถ้ารายการของคุณเป็นรายการเช่น a = [[0,0], [1,0]] และ b = [[2,3], [0,0]]
Schneems

3
สิ่งที่จะเป็นความซับซ้อนเวลาของตัวอย่างแรกset(a) & set(b)?
AdjunctProfessorFalcon

หมายเหตุสิ่งนี้ใช้ไม่ได้หากทั้งสองชุดว่างเปล่าและคุณคาดหวังว่าจะเปรียบเทียบ ดังนั้นเปลี่ยนเป็น "(set (a) และ set (b)) หรือ (ไม่ใช่ a และไม่ใช่ b)"
Neil McGill

395

ใช้set.intersection ()มันรวดเร็วและอ่านได้

>>> set(a).intersection(b)
set([5])

28
คำตอบนี้มีประสิทธิภาพอัลกอริทึมที่ดีเนื่องจากมีเพียงหนึ่งในรายการ (ควรสั้นกว่าที่ต้องการ) กลายเป็นชุดสำหรับการค้นหาอย่างรวดเร็วและรายการอื่น ๆ จะสำรวจภายในรายการในชุด
u0b34a0f6ae

18
bool(set(a).intersection(b))สำหรับTrueหรือFalse
Akshay

6
คำตอบนี้มีความยืดหยุ่นมากขึ้นและสามารถอ่านได้ตั้งแต่คนอาจต้องหรือdifference union
Shihe Zhang

ถ้าฉันมีวัตถุเป็นองค์ประกอบรายการและต้องการจับคู่บางส่วนเท่านั้นกล่าวคือมีเพียงบางแอตทริบิวต์เท่านั้นที่ต้องจับคู่เพื่อให้ถือว่าเป็นวัตถุที่ตรงกัน
CGFoX

มีความแตกต่างของประสิทธิภาพสำหรับ.intersection()vs &หรือไม่
brandonbanks

106

การทดสอบประสิทธิภาพอย่างรวดเร็วซึ่งแสดงให้เห็นถึงวิธีการแก้ปัญหาของ Lutz นั้นดีที่สุด:

import time

def speed_test(func):
    def wrapper(*args, **kwargs):
        t1 = time.time()
        for x in xrange(5000):
            results = func(*args, **kwargs)
        t2 = time.time()
        print '%s took %0.3f ms' % (func.func_name, (t2-t1)*1000.0)
        return results
    return wrapper

@speed_test
def compare_bitwise(x, y):
    set_x = frozenset(x)
    set_y = frozenset(y)
    return set_x & set_y

@speed_test
def compare_listcomp(x, y):
    return [i for i, j in zip(x, y) if i == j]

@speed_test
def compare_intersect(x, y):
    return frozenset(x).intersection(y)

# Comparing short lists
a = [1, 2, 3, 4, 5]
b = [9, 8, 7, 6, 5]
compare_bitwise(a, b)
compare_listcomp(a, b)
compare_intersect(a, b)

# Comparing longer lists
import random
a = random.sample(xrange(100000), 10000)
b = random.sample(xrange(100000), 10000)
compare_bitwise(a, b)
compare_listcomp(a, b)
compare_intersect(a, b)

นี่คือผลลัพธ์ในเครื่องของฉัน:

# Short list:
compare_bitwise took 10.145 ms
compare_listcomp took 11.157 ms
compare_intersect took 7.461 ms

# Long list:
compare_bitwise took 11203.709 ms
compare_listcomp took 17361.736 ms
compare_intersect took 6833.768 ms

เห็นได้ชัดว่าการทดสอบประสิทธิภาพเทียมควรใช้เกลือเม็ดหนึ่ง แต่เนื่องจากset().intersection()คำตอบนั้นเร็วอย่างน้อยที่สุดเท่าที่โซลูชันอื่น ๆ และที่อ่านได้ง่ายที่สุดจึงควรเป็นโซลูชันมาตรฐานสำหรับปัญหาทั่วไปนี้


การตั้งค่าเป็นการลบการทำซ้ำดังนั้นในกรณีของฉันจะไม่ทำงาน
rgralma

@rgralma ทำใหม่setจากที่มีอยู่จะไม่ลบอะไรไปจากเดิมlist listหากคุณต้องการตรรกะพิเศษในการจัดการรายการที่ซ้ำกันในรายการฉันคิดว่าคุณจะต้องถามคำถามใหม่เพราะคำตอบจะต้องเจาะจงกับวิธีการจัดการรายการที่ซ้ำกัน
Joshmaker




14
>>> s = ['a','b','c']   
>>> f = ['a','b','d','c']  
>>> ss= set(s)  
>>> fs =set(f)  
>>> print ss.intersection(fs)   
   **set(['a', 'c', 'b'])**  
>>> print ss.union(fs)        
   **set(['a', 'c', 'b', 'd'])**  
>>> print ss.union(fs)  - ss.intersection(fs)   
   **set(['d'])**

1
คำตอบที่ยอมรับใช้ไม่ได้กับรายการที่มีสตริง อันนี้ทำ
Antony

12

นอกจากนี้คุณสามารถลองสิ่งนี้ได้โดยเก็บองค์ประกอบทั่วไปไว้ในรายการใหม่

new_list = []
for element in a:
    if element in b:
        new_list.append(element)

5

คุณต้องการรายการซ้ำหรือไม่ ถ้าไม่ใช่คุณควรใช้ชุดแทน:


>>> set([1, 2, 3, 4, 5]).intersection(set([9, 8, 7, 6, 5]))
set([5])

หากคุณต้องการรายการจริงๆjava2s.com/Code/Python/List/Functiontointersecttwolists.htm >>> intersect ([1, 2, 3, 4, 5], [9, 8, 7, 6, 5]) [5 ]
Timothy Pratley

อ้างอิงจากเอกสาร - ... ห้ามไม่ให้มีการสร้างข้อผิดพลาดเช่น Set ('abc') & 'cbs' เพื่อให้สามารถอ่านได้ง่ายขึ้น Set ('abc') intersection ('cbs') - docs.python.org/library/sets.html
Aaron Newton

5

อีกวิธีที่ใช้งานได้มากขึ้นในการตรวจสอบความเท่าเทียมกันของรายการสำหรับรายการ 1 (lst1) และรายการ 2 (lst2) โดยที่วัตถุมีความลึกหนึ่งและที่รักษาลำดับไว้คือ:

all(i == j for i, j in zip(lst1, lst2))   

4
a = [1, 2, 3, 4, 5]
b = [9, 8, 7, 6, 5]

lista =set(a)
listb =set(b)   
print listb.intersection(lista)   
returnMatches = set(['5']) #output 

print " ".join(str(return) for return in returnMatches ) # remove the set()   

 5        #final output 

ในขณะที่รหัสนี้อาจตอบคำถามให้บริบทเพิ่มเติมเกี่ยวกับวิธีการและ / หรือทำไมมันแก้ปัญหาจะปรับปรุงค่าระยะยาวของคำตอบ
Donald Duck



3

คุณสามารถใช้ได้:

a = [1, 3, 4, 5, 9, 6, 7, 8]
b = [1, 7, 0, 9]
same_values = set(a) & set(b)
print same_values

เอาท์พุท:

set([1, 7, 9])

4
สิ่งนี้แตกต่างจากคำตอบที่ได้รับการยอมรับเมื่อ 6 ปีที่แล้วหรือไม่
tmdavison

1
ฉันเขียนรายละเอียดพร้อมผลลัพธ์และดีสำหรับผู้เริ่มต้น
Adnan Ghaffar

2

หากคุณต้องการค่าบูลีน:

>>> a = [1, 2, 3, 4, 5]
>>> b = [9, 8, 7, 6, 5]
>>> set(b) == set(a)  & set(b) and set(a) == set(a) & set(b)
False
>>> a = [3,1,2]
>>> b = [1,2,3]
>>> set(b) == set(a)  & set(b) and set(a) == set(a) & set(b)
True

1

โซลูชันต่อไปนี้ใช้ได้กับรายการในลำดับใดก็ได้และยังรองรับทั้งสองรายการให้มีความยาวต่างกัน

import numpy as np
def getMatches(a, b):
    matches = []
    unique_a = np.unique(a)
    unique_b = np.unique(b)
    for a in unique_a:
        for b in unique_b:
            if a == b:
                matches.append(a)
    return matches
print(getMatches([1, 2, 3, 4, 5], [9, 8, 7, 6, 5, 9])) # displays [5]
print(getMatches([1, 2, 3], [3, 4, 5, 1])) # displays [1, 3]

1
Numpy มีฟังก์ชั่นเฉพาะสำหรับ:np.intersect1d(list1, list2)
obchardon

0

การใช้__and__วิธีการแอตทริบิวต์ยังใช้งานได้

>>> a = [1, 2, 3, 4, 5]
>>> b = [9, 8, 7, 6, 5]
>>> set(a).__and__(set(b))
set([5])

หรือเพียงแค่

>>> set([1, 2, 3, 4, 5]).__and__(set([9, 8, 7, 6, 5]))
set([5])
>>>    

0
you can | for set union and & for set intersection.
for example:

    set1={1,2,3}
    set2={3,4,5}
    print(set1&set2)
    output=3

    set1={1,2,3}
    set2={3,4,5}
    print(set1|set2)
    output=1,2,3,4,5

curly braces in the answer.

4
คำถามสำหรับรายการและไม่มีการตั้งค่า การใช้&โอเปอเรเตอร์ที่ตั้งไว้ตอบโดย SilentGhost ในคำตอบที่ยอมรับแล้ว
dWinder

0

ฉันเพิ่งใช้สิ่งต่อไปนี้และได้ผลกับฉัน:

group1 = [1, 2, 3, 4, 5]
group2 = [9, 8, 7, 6, 5]

for k in group1:
    for v in group2:
        if k == v:
            print(k)

สิ่งนี้จะพิมพ์ 5 ในกรณีของคุณ อาจจะไม่ได้ประสิทธิภาพที่ดีนัก

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