จะหารายการแยกได้อย่างไร


203
a = [1,2,3,4,5]
b = [1,3,5,6]
c = a and b
print c

เอาต์พุตจริง: [1,3,5,6] เอาต์พุตที่คาดหวัง:[1,3,5]

เราจะใช้การดำเนินการบูลีน AND (การแยกรายการ) ในสองรายการได้อย่างไร


6
ปัญหาที่นี่คือที่a and bทำงานเหมือนคำสั่งต่อไปนี้จากเอกสารระบุว่า: " การแสดงออกx and yครั้งแรกประเมินxถ้าxเป็นเท็จค่าของมันจะถูกส่งกลับมิฉะนั้นyจะได้รับการประเมินและส่งกลับค่าผลลัพธ์ "
Tadeck

คำตอบ:


347

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

>>> a = [1,2,3,4,5]
>>> b = [1,3,5,6]
>>> list(set(a) & set(b))
[1, 3, 5]

9
สิ่งที่ถ้าa = [1,1,2,3,4,5]และb = [1,1,3,5,6]แล้วแยกเป็น[1,1,3,5]แต่วิธีการดังกล่าวจะส่งผลให้มีเพียงคนเดียว1คือ[1, 3, 5]สิ่งที่จะเป็นวิธีการเขียนที่จะทำมันแล้ว?
Nitish Kumar Pal

6
@NItishKumarPal intersectionเป็นที่เข้าใจกันโดยทั่วไปว่าจะตั้งค่าตาม คุณกำลังมองหาสัตว์ที่แตกต่างออกไปเล็กน้อย - และคุณอาจต้องทำด้วยตนเองโดยการเรียงลำดับแต่ละรายการและรวมผลลัพธ์ - และรักษา dups ในการผสาน
javadba

1
@MarkByers สิ่งนี้จะไม่ซ้ำกันซ้ำ ๆ
javadba

84

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

[x for x in a if x in b]

หรือ "ค่า x ทั้งหมดที่อยู่ใน A หากค่า X เป็น B"


1
ดูเหมือนว่าจะเป็นเสียงไพเราะที่สุดที่รักษาความสงบเรียบร้อย ไม่แน่ใจว่าทำไมสิ่งนี้ถึงไม่ได้ถูกยกระดับขึ้น !! ขอบคุณสำหรับทางออกที่ดี!
Bill D

15
นี่เป็นวิธีแก้ปัญหา O (n ^ 2) ในขณะที่วิธีแก้ปัญหาข้างต้นคือ O (n)
nareddyt

3
@nareddyt - จัดbเซ็ทและคุณจะมี O (n)
jcchuks

2
@jcchuks ข้อดีของการแก้ปัญหานี้คือถ้าคุณต้องการเก็บข้อมูลที่ซ้ำกัน หากคุณมั่นใจในความไม่เหมือนใครโซลูชันชุด O (n) จะดีกว่า อย่างไรก็ตามหากทำซ้ำไม่ได้ทำไม OP ถึงพูดถึงรายการต่าง ๆ ด้วย แนวคิดของการแยกรายการเป็นความไร้สาระทางคณิตศาสตร์
demongolem

63

หากคุณแปลงใหญ่กว่าของสองรายการเป็นชุดคุณสามารถได้จุดตัดของชุดนั้นด้วย iterable ใด ๆ โดยใช้intersection():

a = [1,2,3,4,5]
b = [1,3,5,6]
set(a).intersection(b)

9
นี่คือสิ่งที่แตกต่างจากlist(set(a) & set(b))
user1767754

3
เหตุใดจึงมีความสำคัญว่ารายการใดถูกแปลงเป็นชุด (สมมติว่า n! = m) อะไรคือข้อดีของการแปลงเพียงรายการเดียวเพื่อตั้งค่า
3pitt

1
ดูเหมือนว่าเรื่องนี้จะเร็วขึ้น
นาธาน

29

สร้างชุดที่มีขนาดใหญ่กว่า:

_auxset = set(a)

จากนั้น

c = [x for x in b if x in _auxset]

จะทำในสิ่งที่คุณต้องการ (การรักษาbของการสั่งซื้อไม่ได้a's - สามารถไม่จำเป็นต้องรักษาทั้งสอง ) และทำมันได้อย่างรวดเร็ว (การใช้if x in aเป็นเงื่อนไขในรายการความเข้าใจก็สามารถใช้ได้และหลีกเลี่ยงความจำเป็นในการสร้าง_auxsetแต่น่าเสียดายที่รายการที่มีความยาวมากจะช้ากว่ามาก)

หากคุณต้องการให้ผลลัพธ์เรียงลำดับแทนที่จะเรียงลำดับรายการอย่างใดอย่างหนึ่งอาจเป็นวิธีที่ neater:

c = sorted(set(a).intersection(b))

นี่เกือบจะช้ากว่าคำตอบที่ยอมรับ แต่มีข้อได้เปรียบที่ไม่ซ้ำซ้อน
tripleee

18

ต่อไปนี้เป็นโค้ด Python 2 / Python 3 บางตัวที่สร้างข้อมูลเวลาสำหรับทั้งวิธีแบบรายการและแบบตั้งค่าในการค้นหาจุดตัดของสองรายการ

อัลกอริธึมความเข้าใจในรายการบริสุทธิ์คือ O (n ^ 2) เนื่องจากinในรายการนั้นเป็นการค้นหาเชิงเส้น อัลกอริธึมที่ใช้ชุดการทำงานคือ O (n) เนื่องจากการค้นหาชุดคือ O (1) และการสร้างชุดคือ O (n) (และการแปลงชุดให้เป็นรายการก็คือ O (n) ดังนั้นสำหรับn ที่มีขนาดใหญ่พออัลกอริธึมที่ตั้งค่าได้เร็วขึ้น แต่สำหรับn ที่มีขนาดเล็กค่าใช้จ่ายในการสร้างชุดทำให้ช้าลงกว่าอัลกอริธึมรายการแบบบริสุทธิ์

#!/usr/bin/env python

''' Time list- vs set-based list intersection
    See http://stackoverflow.com/q/3697432/4014959
    Written by PM 2Ring 2015.10.16
'''

from __future__ import print_function, division
from timeit import Timer

setup = 'from __main__ import a, b'
cmd_lista = '[u for u in a if u in b]'
cmd_listb = '[u for u in b if u in a]'

cmd_lcsa = 'sa=set(a);[u for u in b if u in sa]'

cmd_seta = 'list(set(a).intersection(b))'
cmd_setb = 'list(set(b).intersection(a))'

reps = 3
loops = 50000

def do_timing(heading, cmd, setup):
    t = Timer(cmd, setup)
    r = t.repeat(reps, loops)
    r.sort()
    print(heading, r)
    return r[0]

m = 10
nums = list(range(6 * m))

for n in range(1, m + 1):
    a = nums[:6*n:2]
    b = nums[:6*n:3]
    print('\nn =', n, len(a), len(b))
    #print('\nn = %d\n%s %d\n%s %d' % (n, a, len(a), b, len(b)))
    la = do_timing('lista', cmd_lista, setup) 
    lb = do_timing('listb', cmd_listb, setup) 
    lc = do_timing('lcsa ', cmd_lcsa, setup)
    sa = do_timing('seta ', cmd_seta, setup)
    sb = do_timing('setb ', cmd_setb, setup)
    print(la/sa, lb/sa, lc/sa, la/sb, lb/sb, lc/sb)

เอาท์พุต

n = 1 3 2
lista [0.082171916961669922, 0.082588911056518555, 0.0898590087890625]
listb [0.069530963897705078, 0.070394992828369141, 0.075379848480224609]
lcsa  [0.11858987808227539, 0.1188349723815918, 0.12825107574462891]
seta  [0.26900982856750488, 0.26902294158935547, 0.27298116683959961]
setb  [0.27218389511108398, 0.27459001541137695, 0.34307217597961426]
0.305460649521 0.258469975867 0.440838458259 0.301898526833 0.255455833892 0.435697630214

n = 2 6 4
lista [0.15915989875793457, 0.16000485420227051, 0.16551494598388672]
listb [0.13000702857971191, 0.13060092926025391, 0.13543915748596191]
lcsa  [0.18650484085083008, 0.18742108345031738, 0.19513416290283203]
seta  [0.33592700958251953, 0.34001994132995605, 0.34146714210510254]
setb  [0.29436492919921875, 0.2953648567199707, 0.30039691925048828]
0.473793098554 0.387009751735 0.555194537893 0.540689066428 0.441652573672 0.633583767462

n = 3 9 6
lista [0.27657914161682129, 0.28098297119140625, 0.28311991691589355]
listb [0.21585917472839355, 0.21679902076721191, 0.22272896766662598]
lcsa  [0.22559309005737305, 0.2271728515625, 0.2323150634765625]
seta  [0.36382699012756348, 0.36453008651733398, 0.36750602722167969]
setb  [0.34979605674743652, 0.35533690452575684, 0.36164689064025879]
0.760194128313 0.59330170819 0.62005595016 0.790686848184 0.61710008036 0.644927481902

n = 4 12 8
lista [0.39616990089416504, 0.39746403694152832, 0.41129183769226074]
listb [0.33485794067382812, 0.33914685249328613, 0.37850618362426758]
lcsa  [0.27405810356140137, 0.2745978832244873, 0.28249192237854004]
seta  [0.39211201667785645, 0.39234519004821777, 0.39317893981933594]
setb  [0.36988520622253418, 0.37011313438415527, 0.37571001052856445]
1.01034878821 0.85398540833 0.698928091731 1.07106176249 0.905302334456 0.740927452493

n = 5 15 10
lista [0.56792402267456055, 0.57422614097595215, 0.57740211486816406]
listb [0.47309303283691406, 0.47619009017944336, 0.47628307342529297]
lcsa  [0.32805585861206055, 0.32813096046447754, 0.3349759578704834]
seta  [0.40036201477050781, 0.40322518348693848, 0.40548801422119141]
setb  [0.39103078842163086, 0.39722800254821777, 0.43811702728271484]
1.41852623806 1.18166313332 0.819398061028 1.45237674242 1.20986133789 0.838951479847

n = 6 18 12
lista [0.77897095680236816, 0.78187918663024902, 0.78467702865600586]
listb [0.629547119140625, 0.63210701942443848, 0.63321495056152344]
lcsa  [0.36563992500305176, 0.36638498306274414, 0.38175487518310547]
seta  [0.46695613861083984, 0.46992206573486328, 0.47583580017089844]
setb  [0.47616910934448242, 0.47661614418029785, 0.4850609302520752]
1.66818870637 1.34819326075 0.783028414812 1.63591241329 1.32210827369 0.767878297495

n = 7 21 14
lista [0.9703209400177002, 0.9734041690826416, 1.0182771682739258]
listb [0.82394003868103027, 0.82625699043273926, 0.82796716690063477]
lcsa  [0.40975093841552734, 0.41210508346557617, 0.42286920547485352]
seta  [0.5086359977722168, 0.50968098640441895, 0.51014018058776855]
setb  [0.48688101768493652, 0.4879908561706543, 0.49204087257385254]
1.90769222837 1.61990115188 0.805587768483 1.99293236904 1.69228211566 0.841583309951

n = 8 24 16
lista [1.204819917678833, 1.2206029891967773, 1.258256196975708]
listb [1.014998197555542, 1.0206191539764404, 1.0343101024627686]
lcsa  [0.50966787338256836, 0.51018595695495605, 0.51319599151611328]
seta  [0.50310111045837402, 0.50556015968322754, 0.51335406303405762]
setb  [0.51472997665405273, 0.51948785781860352, 0.52113485336303711]
2.39478683834 2.01748351664 1.01305257092 2.34068341135 1.97190418975 0.990165516871

n = 9 27 18
lista [1.511646032333374, 1.5133969783782959, 1.5639569759368896]
listb [1.2461750507354736, 1.254518985748291, 1.2613379955291748]
lcsa  [0.5565330982208252, 0.56119203567504883, 0.56451296806335449]
seta  [0.5966339111328125, 0.60275578498840332, 0.64791703224182129]
setb  [0.54694414138793945, 0.5508568286895752, 0.55375313758850098]
2.53362406013 2.08867620074 0.932788243907 2.76380331728 2.27843203069 1.01753187594

n = 10 30 20
lista [1.7777848243713379, 2.1453688144683838, 2.4085969924926758]
listb [1.5070111751556396, 1.5202279090881348, 1.5779800415039062]
lcsa  [0.5954139232635498, 0.59703707695007324, 0.60746097564697266]
seta  [0.61563014984130859, 0.62125110626220703, 0.62354087829589844]
setb  [0.56723213195800781, 0.57257509231567383, 0.57460403442382812]
2.88774814689 2.44791645689 0.967161734066 3.13413984189 2.6567803378 1.04968299523

สร้างโดยใช้เครื่องแกนเดี่ยว 2GHz พร้อม RAM 2GB ใช้ Python 2.6.6 บนเดเบียนรสชาติของ Linux (ด้วย Firefox ที่ทำงานในพื้นหลัง)

ตัวเลขเหล่านี้เป็นเพียงแนวทางคร่าวๆเนื่องจากความเร็วที่แท้จริงของอัลกอริทึมต่างๆนั้นได้รับผลกระทบแตกต่างกันตามสัดส่วนขององค์ประกอบที่อยู่ในรายการแหล่งที่มาทั้งสอง


11
a = [1,2,3,4,5]
b = [1,3,5,6]
c = list(set(a).intersection(set(b)))

ควรทำงานเหมือนฝัน และถ้าเป็นไปได้ให้ใช้ชุดแทนที่จะเป็นรายการเพื่อหลีกเลี่ยงการเปลี่ยนประเภทนี้!


ถ้าaและbมีขนาดใหญ่นี่จะเร็วกว่าคำตอบอื่น ๆ
javadba

5

วิธีการทำงานสามารถทำได้โดยใช้filterและlambdaผู้ประกอบการ

list1 = [1,2,3,4,5,6]

list2 = [2,4,6,9,10]

>>> list(filter(lambda x:x in list1, list2))

[2, 4, 6]

แก้ไข: มันกรอง x ที่มีอยู่ในทั้ง list1 และ list, สามารถตั้งค่าความแตกต่างได้โดยใช้:

>>> list(filter(lambda x:x not in list1, list2))
[9,10]

แก้ไข 2: python3 filterส่งคืนวัตถุตัวกรองห่อหุ้มด้วยlistส่งคืนรายการผลลัพธ์


โปรดใช้ลิงก์แก้ไขเพื่ออธิบายวิธีการทำงานของรหัสนี้และไม่เพียง แต่ให้รหัสเนื่องจากคำอธิบายมีแนวโน้มที่จะช่วยผู้อ่านในอนาคต ดูเพิ่มเติมวิธีการตอบ แหล่งที่มา
Jed Fox

1
ด้วย Python3 สิ่งนี้จะคืนค่าวัตถุตัวกรอง คุณต้องพูดlist(filter(lambda x:x in list1, list2))เพื่อให้มันเป็นรายการ
Adrian W

1

นี่คือตัวอย่างเมื่อคุณต้องการแต่ละองค์ประกอบในผลลัพธ์ควรปรากฏหลายครั้งตามที่แสดงในทั้งสองอาร์เรย์

def intersection(nums1, nums2):
    #example:
    #nums1 = [1,2,2,1]
    #nums2 = [2,2]
    #output = [2,2]
    #find first 2 and remove from target, continue iterating

    target, iterate = [nums1, nums2] if len(nums2) >= len(nums1) else [nums2, nums1] #iterate will look into target

    if len(target) == 0:
            return []

    i = 0
    store = []
    while i < len(iterate):

         element = iterate[i]

         if element in target:
               store.append(element)
               target.remove(element)

         i += 1


    return store

1

มันอาจจะสาย แต่ฉันคิดว่าฉันควรจะแบ่งปันในกรณีที่คุณต้องทำด้วยตนเอง (แสดงผล - ฮ่าฮ่า) หรือเมื่อคุณต้องการให้องค์ประกอบทั้งหมดปรากฏขึ้นหลายครั้งเท่าที่จะเป็นไปได้หรือเมื่อคุณต้องการให้มันเป็นเอกลักษณ์ .

โปรดทราบว่าการทดสอบนั้นถูกเขียนขึ้นสำหรับมัน



    from nose.tools import assert_equal

    '''
    Given two lists, print out the list of overlapping elements
    '''

    def overlap(l_a, l_b):
        '''
        compare the two lists l_a and l_b and return the overlapping
        elements (intersecting) between the two
        '''

        #edge case is when they are the same lists
        if l_a == l_b:
            return [] #no overlapping elements

        output = []

        if len(l_a) == len(l_b):
            for i in range(l_a): #same length so either one applies
                if l_a[i] in l_b:
                    output.append(l_a[i])

            #found all by now
            #return output #if repetition does not matter
            return list(set(output))

        else:
            #find the smallest and largest lists and go with that
            sm = l_a if len(l_a)  len(l_b) else l_b

            for i in range(len(sm)):
                if sm[i] in lg:
                    output.append(sm[i])

            #return output #if repetition does not matter
            return list(set(output))

    ## Test the Above Implementation

    a = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
    b = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
    exp = [1, 2, 3, 5, 8, 13]

    c = [4, 4, 5, 6]
    d = [5, 7, 4, 8 ,6 ] #assuming it is not ordered
    exp2 = [4, 5, 6]

    class TestOverlap(object):

        def test(self, sol):
            t = sol(a, b)
            assert_equal(t, exp)
            print('Comparing the two lists produces')
            print(t)

            t = sol(c, d)
            assert_equal(t, exp2)
            print('Comparing the two lists produces')
            print(t)

            print('All Tests Passed!!')

    t = TestOverlap()
    t.test(overlap)


0

คุณสามารถใช้เคาน์เตอร์ได้! มันไม่รักษาคำสั่งซื้อ แต่จะพิจารณารายการที่ซ้ำกัน:

>>> from collections import Counter
>>> a = [1,2,3,4,5]
>>> b = [1,3,5,6]
>>> d1, d2 = Counter(a), Counter(b)
>>> c = [n for n in d1.keys() & d2.keys() for _ in range(min(d1[n], d2[n]))]
>>> print(c)
[1,3,5]
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.