การเปรียบเทียบองค์ประกอบทั่วไประหว่าง 2 รายการ


143
def common_elements(list1, list2):
    """
    Return a list containing the elements which are in both list1 and list2

    >>> common_elements([1,2,3,4,5,6], [3,5,7,9])
    [3, 5]
    >>> common_elements(['this','this','n','that'],['this','not','that','that'])
    ['this', 'that']
    """
    for element in list1:
        if element in list2:
            return list(element)

จนถึงตอนนี้ แต่ดูเหมือนจะไม่สามารถใช้งานได้!

ความคิดใด ๆ


1
สวัสดีคุณช่วยเพิ่มรายละเอียดเกี่ยวกับวิธีการใช้รหัสได้ไหม ถ้านี่คือการมอบหมายให้เสร็จสมบูรณ์มันอาจจะดีกว่าที่จะเลือกวิธีการแก้ปัญหาที่หุ้มวิธี "Pythonic" อย่างไรก็ตามหากความกังวลเกี่ยวกับประสิทธิภาพของคุณวิธีการ "Pythonic" นั้นไม่น่าจะเป็นทางออกที่มีประสิทธิภาพที่สุด การให้คำปรึกษากับเราเกี่ยวกับรายละเอียดเหล่านี้จะช่วยให้การแก้ปัญหามีเป้าหมายเพื่อแก้ปัญหาของคุณ
แมตต์ซี

คำตอบ:


278
>>> list1 = [1,2,3,4,5,6]
>>> list2 = [3, 5, 7, 9]
>>> list(set(list1).intersection(list2))
[3, 5]

1
+1 แต่ส่วนตัวฉันใช้ frozenset เพราะมันไม่เปลี่ยนรูปแบบและสามารถใช้เป็นคีย์พจนานุกรมเป็นต้น
zebrabox

19
สิ่งนี้จะส่งคืนองค์ประกอบ / ที่ไม่ซ้ำกัน / ทั่วไป แต่จะไม่มีองค์ประกอบซ้ำ ๆ ที่อาจมีอยู่
Dologan

@SilentGhost วิธีรับจำนวนองค์ประกอบที่ตรงกันจากสองรายการ ในกรณีนี้คือ 2
Poka

@Poka len (list (set (list1) .interection (list2)))
Dharmanshu Kamra

2
FYI เร็วกว่าวิธีการแก้ปัญหาที่เสนอโดยTamás แต่สำหรับกรณีการใช้งานที่ฉันดูเมื่อฉันลงเอยด้วยหน้านี้เป็นสิ่งสำคัญที่จะต้องรักษาลำดับดั้งเดิมขององค์ประกอบสำหรับองค์ประกอบที่ผ่านการกรอง วิธีการนี้จะสูญเสียคำสั่งในขณะที่วิธีการรายการความเข้าใจรักษาคำสั่งซื้อ สำคัญถ้าใครต้องพิจารณาเรื่องนี้ ขอบคุณ
agftrading

41

คุณยังสามารถใช้ชุดและรับค่าปกติในหนึ่งบรรทัด: ลบชุดที่มีความแตกต่างจากชุดใดชุดหนึ่ง

A = [1,2,3,4]
B = [2,4,7,8]
commonalities = set(A) - (set(A) - set(B))

4
นี่เป็นการแปลง A เพื่อตั้งค่าสองครั้งสิ้นเปลืองโดยไม่จำเป็น
Wim

36

โซลูชันที่แนะนำโดยS.MarkและSilentGhostมักบอกคุณว่าควรทำอย่างไรในแบบ Pythonic แต่ฉันคิดว่าคุณอาจได้รับประโยชน์จากการทราบว่าเหตุใดโซลูชันของคุณจึงไม่ทำงาน ปัญหาคือทันทีที่คุณพบองค์ประกอบทั่วไปแรกในสองรายการคุณคืนองค์ประกอบเดียวเท่านั้น โซลูชันของคุณสามารถแก้ไขได้โดยการสร้างresultรายการและรวบรวมองค์ประกอบทั่วไปในรายการนั้น:

def common_elements(list1, list2):
    result = []
    for element in list1:
        if element in list2:
            result.append(element)
    return result

เวอร์ชันที่สั้นกว่าโดยใช้รายการความเข้าใจ:

def common_elements(list1, list2):
    return [element for element in list1 if element in list2]

อย่างไรก็ตามอย่างที่ฉันบอกว่านี่เป็นวิธีที่ไม่มีประสิทธิภาพในการทำเช่นนี้ - ชุดแบบในตัวของ Python นั้นมีประสิทธิภาพมากกว่าในแบบที่ใช้ใน C


1
ดีมากสำหรับข้อเสนอทั้งสอง
dlewin

1
หมายเหตุ: วิธีการข้างต้นจะใช้ได้กับรายการที่มีขนาดเท่ากันเท่านั้น หากคุณกำลังทำงานกับรายการขนาดไม่เท่าที่ฉันเป็นคุณจะต้องประเมินลำดับตาม len () ก่อนการเรียกใช้ฟังก์ชัน: list1 = [2,2,2], list2 [2,3] -> [2,2,2] list1 = [2,3], list2 [2,2,2] -> [2]
redthumb

29

ใช้ชุดจุดตัดชุด set (list1) และ set (list2)

>>> def common_elements(list1, list2):
...     return list(set(list1) & set(list2))
...
>>>
>>> common_elements([1,2,3,4,5,6], [3,5,7,9])
[3, 5]
>>>
>>> common_elements(['this','this','n','that'],['this','not','that','that'])
['this', 'that']
>>>
>>>

โปรดทราบว่ารายการผลลัพธ์อาจแตกต่างกับรายการต้นฉบับ


ขอบคุณสำหรับความช่วยเหลือ ทำความเข้าใจกับสิ่งที่ฉันผิดไปและสิ่งที่ต้องทำในครั้งต่อไป :)
แดเนียล

5
ทางออกที่ดี มีวิธีรักษาความสงบเรียบร้อยด้วยหรือไม่?
tarrasch


9

Set เป็นอีกวิธีที่เราสามารถแก้ปัญหานี้ได้

a = [3,2,4]
b = [2,3,5]
set(a)&set(b)
{2, 3}

9

list1 = [1,2,3,4,5,6] list2 = [3,5,7,9]

ฉันรู้ว่า 3 วิธีสามารถแก้ปัญหานี้ได้แน่นอนอาจมีมากกว่านี้

1-

common_elements = [e for e in list1 if e in list2]

2-

import numpy as np
common_elements = np.intersect1d(list1, list2)

3-

common_elements = set(list1).intersection(list2)

วิธีที่ 3 เป็นวิธีที่เร็วที่สุดเนื่องจากชุดนำมาใช้โดยใช้ตารางแฮช


8

คำตอบก่อนหน้าทั้งหมดทำงานเพื่อค้นหาองค์ประกอบทั่วไปที่ไม่ซ้ำกัน แต่จะไม่บัญชีสำหรับรายการซ้ำในรายการ หากคุณต้องการให้องค์ประกอบทั่วไปปรากฏในหมายเลขเดียวกับที่พบได้ทั่วไปในรายการคุณสามารถใช้หนึ่งซับต่อไปนี้:

l2, common = l2[:], [ e for e in l1 if e in l2 and (l2.pop(l2.index(e)) or True)]

or Trueส่วนหนึ่งเป็นสิ่งที่จำเป็นเท่านั้นถ้าคุณคาดหวังว่าองค์ประกอบใด ๆ Falseที่จะประเมิน


วิธีแก้ปัญหาที่ยอดเยี่ยมดูเหมือนจะละเอียดที่สุดถ้า
เฮฮาน้อยลง

นี่ควรเป็นคำตอบที่ควรเลือก! ฉันสมมติว่ามันใช้ได้กับรายการที่ไม่เท่ากัน นอกจากนี้โซลูชันส่วนใหญ่ใช้setซึ่งไม่เสถียร (คำสั่งจะหายไป)
อายุการใช้งาน

7

ฉันเปรียบเทียบแต่ละวิธีที่แต่ละคำตอบกล่าวถึง ในตอนนี้ฉันใช้ python 3.6.3 สำหรับการติดตั้งนี้ นี่คือรหัสที่ฉันใช้:

import time
import random
from decimal import Decimal


def method1():
    common_elements = [x for x in li1_temp if x in li2_temp]
     print(len(common_elements))


def method2():
    common_elements = (x for x in li1_temp if x in li2_temp)
    print(len(list(common_elements)))


def method3():
    common_elements = set(li1_temp) & set(li2_temp)
    print(len(common_elements))


def method4():
    common_elements = set(li1_temp).intersection(li2_temp)
    print(len(common_elements))


if __name__ == "__main__":
    li1 = []
    li2 = []
    for i in range(100000):
        li1.append(random.randint(0, 10000))
        li2.append(random.randint(0, 10000))

    li1_temp = list(set(li1))
    li2_temp = list(set(li2))

    methods = [method1, method2, method3, method4]
    for m in methods:
        start = time.perf_counter()
        m()
        end = time.perf_counter()
        print(Decimal((end - start)))

ถ้าคุณเรียกใช้รหัสนี้คุณจะเห็นว่าถ้าคุณใช้ list หรือ generator (ถ้าคุณวนซ้ำกับ generator ไม่เพียงแค่ใช้มันฉันทำอย่างนี้เมื่อฉันบังคับให้เครื่องกำเนิดไฟฟ้าพิมพ์ความยาวของมัน) คุณจะได้รับประสิทธิภาพเดียวกัน แต่ถ้าคุณใช้ชุดคุณจะได้รับประสิทธิภาพที่ดีขึ้นมาก นอกจากนี้หากคุณใช้วิธีการทางแยกคุณจะได้รับประสิทธิภาพที่ดีขึ้นเล็กน้อย ผลลัพธ์ของแต่ละวิธีในคอมพิวเตอร์ของฉันอยู่ในรายการตะโกน:

  1. วิธีที่ 1: 0.8150673999999999974619413478649221360683441
  2. วิธีที่ 2: 0.8329545000000001531148541289439890533685684
  3. วิธีที่ 3: 0.0016547000000000089414697868051007390022277
  4. วิธีที่ 4: 0.0010262999999999244948867271887138485908508

5

นี่คือข้อเสนอของ ฉันฉันคิดว่ามันง่ายกว่ากับเซตมากกว่าสำหรับลูป

def unique_common_items(list1, list2):
   # Produce the set of *unique* common items in two lists.
   return list(set(list1) & set(list2))


0

1) วิธีที่ 1 การบันทึก list1 เป็นพจนานุกรมแล้ววนซ้ำแต่ละองค์ประกอบในรายการ 2

def findarrayhash(a,b):
    h1={k:1 for k in a}
    for val in b:
        if val in h1:
            print("common found",val)
            del h1[val]
        else:
            print("different found",val)
    for key in h1.iterkeys():
        print ("different found",key)

ค้นหาองค์ประกอบทั่วไปและแตกต่าง:

2) วิธีที่ 2 โดยใช้ชุด

def findarrayset(a,b):
    common = set(a)&set(b)
    diff=set(a)^set(b)
    print list(common)
    print list(diff) 

-1

ใช้เครื่องกำเนิดไฟฟ้า:

common = (x for x in list1 if x in list2)

ข้อได้เปรียบที่นี่คือสิ่งนี้จะกลับมาในเวลาคงที่ (เกือบจะทันที) แม้ว่าจะใช้รายการขนาดใหญ่หรือ iterables ขนาดใหญ่อื่น ๆ

ตัวอย่างเช่น,

list1 =  list(range(0,10000000))
list2=list(range(1000,20000000))
common = (x for x in list1 if x in list2)

คำตอบอื่น ๆ ทั้งหมดที่นี่จะใช้เวลานานมากสำหรับค่าเหล่านี้สำหรับ list1 และ list2

จากนั้นคุณสามารถย้ำคำตอบด้วย

for i in common: print(i)

หรือแปลงเป็นรายการด้วย

list(i)

สิ่งนี้ไม่ได้สร้างคำตอบ ผลที่ได้คือเครื่องกำเนิดไฟฟ้ามากกว่ารายการขององค์ประกอบทั่วไป
josiekre

1
ถูกต้องมันสร้างเครื่องกำเนิดไฟฟ้าซึ่งเป็นคำตอบ คำถามก็คือเพื่อให้ได้องค์ประกอบทั่วไปของ 2 รายการซึ่งตัวสร้างนี้ทำ for i in common: print(i)เพียงแค่ย้ำกำเนิดไฟฟ้าเช่นดังนั้น: เครื่องกำเนิดไฟฟ้าคือ iterables ที่ใช้บ่อย ๆ แทน iterables อื่น ๆ เช่นรายการ
ประสานงาน
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.