Làm thế nào để tìm danh sách giao?


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

sản lượng thực tế: [1,3,5,6] sản lượng dự kiến:[1,3,5]

Làm thế nào chúng ta có thể đạt được một phép toán Boolean (giao điểm danh sách) trên hai danh sách?


6
Vấn đề ở đây là a and bhoạt động giống như tuyên bố sau từ tài liệu đề cập đến nó: " Biểu thức x and yđầu tiên đánh giá x; nếu xsai, giá trị của nó được trả về; nếu không, yđược đánh giá và giá trị kết quả được trả về. "
Tadeck

Câu trả lời:


347

Nếu thứ tự không quan trọng và bạn không cần phải lo lắng về các bản sao thì bạn có thể sử dụng giao cắt đặt:

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

9
Điều gì xảy ra nếu a = [1,1,2,3,4,5]b = [1,1,3,5,6]sau đó là giao điểm [1,1,3,5]nhưng theo phương pháp trên, nó sẽ chỉ dẫn đến một 1nghĩa là [1, 3, 5]cách viết sẽ làm gì sau đó?
Nitish Kumar Pal

6
@NItishKumarPal intersectionthường được hiểu là được đặt dựa trên. Bạn đang tìm kiếm một con vật hơi khác nhau - và bạn có thể cần phải làm điều đó bằng tay bằng cách sắp xếp từng danh sách và hợp nhất các kết quả - và giữ cho các dups trong việc hợp nhất.
javadba

1
@MarkByer Điều này sẽ không có bản sao.
javadba

85

Sử dụng hiểu danh sách là một điều khá rõ ràng đối với tôi. Không chắc chắn về hiệu suất, nhưng ít nhất mọi thứ ở lại danh sách.

[x for x in a if x in b]

Hoặc "tất cả các giá trị x nằm trong A, nếu giá trị X nằm trong B".


1
điều này có vẻ như pythonic nhất giữ trật tự. không chắc chắn tại sao điều này không được nâng cao hơn !! thx cho giải pháp tuyệt vời!
Bill D

15
Đây là một giải pháp O (n ^ 2), trong khi các giải pháp trên là O (n)
nareddyt

3
@nareddyt - tạo bmột bộ và bạn sẽ có O (n)
jcchuks

2
@jcchuks Ưu điểm của giải pháp này là nếu bạn cần giữ lại các bản sao. Nếu bạn có thể chắc chắn về tính duy nhất, thì giải pháp thiết lập O (n) sẽ tốt hơn. Tuy nhiên, nếu không thể sao chép, tại sao OP thậm chí còn nói về danh sách để bắt đầu? Khái niệm giao điểm danh sách là một sự phi lý toán học
demongolem

63

Nếu bạn chuyển đổi danh sách lớn hơn của hai danh sách thành một tập hợp, bạn có thể lấy giao điểm của tập hợp đó với bất kỳ lần lặp nào bằng cách sử dụng intersection():

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

9
Đây có khác gì so vớilist(set(a) & set(b))
user1767754

3
tại sao danh sách nào được chuyển đổi thành tập hợp (giả sử n! = m)? lợi thế của việc chỉ chuyển đổi một để thiết lập là gì?
3pitt

1
Có vẻ như điều này sẽ nhanh hơn
Nathan

29

Tạo một bộ ra khỏi cái lớn hơn:

_auxset = set(a)

Sau đó,

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

sẽ làm những gì bạn muốn (bảo quản bđơn hàng, không phải a- không nhất thiết phải bảo tồn cả hai ) và thực hiện nhanh chóng . (Sử dụng if x in anhư điều kiện trong việc hiểu danh sách cũng sẽ hoạt động và tránh sự cần thiết phải xây dựng_auxset , nhưng thật không may cho các danh sách có độ dài đáng kể, nó sẽ chậm hơn rất nhiều).

Nếu bạn muốn kết quả được sắp xếp, thay vì duy trì thứ tự của danh sách, một cách thậm chí gọn gàng hơn có thể là:

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

Điều này gần như chắc chắn chậm hơn câu trả lời được chấp nhận nhưng có lợi thế là các bản sao không bị mất.
tripleee

18

Dưới đây là một số mã Python 2 / Python 3 tạo thông tin về thời gian cho cả hai phương pháp dựa trên danh sách và dựa trên tập hợp để tìm giao điểm của hai danh sách.

Các thuật toán hiểu danh sách thuần túy là O (n ^ 2), vì introng danh sách là tìm kiếm tuyến tính. Các thuật toán dựa trên tập hợp là O (n), vì tìm kiếm tập hợp là O (1) và tạo tập hợp là O (n) (và chuyển đổi một tập hợp thành một danh sách cũng là O (n)). Vì vậy, đối với n đủ lớn, các thuật toán dựa trên tập hợp sẽ nhanh hơn, nhưng đối với n nhỏ, các chi phí tạo tập hợp làm cho chúng chậm hơn các thuật toán comp danh sách thuần túy.

#!/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)

đầu ra

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

Được tạo bằng máy lõi đơn 2GHz với 2GB RAM chạy Python 2.6.6 trên nền Linux của Linux (với Firefox chạy ở chế độ nền).

Những số liệu này chỉ là một hướng dẫn sơ bộ, vì tốc độ thực tế của các thuật toán khác nhau bị ảnh hưởng khác nhau bởi tỷ lệ các yếu tố có trong cả hai danh sách nguồn.


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

Nên làm việc như mơ. Và, nếu bạn có thể, hãy sử dụng các bộ thay vì danh sách để tránh tất cả loại này thay đổi!


Nếu ab lớn thì điều này nhanh hơn các câu trả lời khác
javadba

5

Một cách chức năng có thể đạt được bằng cách sử dụng filterlambdađiều hành.

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

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

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

[2, 4, 6]

Chỉnh sửa: Nó lọc ra x tồn tại trong cả list1 và list, thiết lập sự khác biệt cũng có thể đạt được bằng cách sử dụng:

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

Edit2: python3 filtertrả về một đối tượng bộ lọc, đóng gói nó với listdanh sách đầu ra.


Vui lòng sử dụng liên kết chỉnh sửa để giải thích cách mã này hoạt động và không chỉ cung cấp mã, vì một lời giải thích có nhiều khả năng giúp người đọc trong tương lai. Xem thêm Cách trả lời . nguồn
Jed Fox

1
Với Python3, điều này trả về một đối tượng bộ lọc. Bạn cần nói list(filter(lambda x:x in list1, list2))để có được nó như là một danh sách.
Adrian W

1

Đây là một ví dụ khi bạn cần Mỗi phần tử trong kết quả sẽ xuất hiện nhiều lần như nó hiển thị trong cả hai mảng.

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

Nó có thể bị trễ nhưng tôi chỉ nghĩ rằng tôi nên chia sẻ cho trường hợp bạn bắt buộc phải thực hiện thủ công (hiển thị hoạt động - haha) HOẶC khi bạn cần tất cả các yếu tố xuất hiện nhiều lần nhất có thể hoặc khi bạn cũng cần nó là duy nhất .

Vui lòng lưu ý rằng các bài kiểm tra cũng đã được viết cho nó.



    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

Nếu, bởi Boolean AND, bạn có nghĩa là các mục xuất hiện trong cả hai danh sách, ví dụ như giao điểm, thì bạn nên xem Python setfrozensetcác loại.


0

Bạn cũng có thể sử dụng một quầy! Nó không bảo toàn thứ tự, nhưng nó sẽ xem xét các bản sao:

>>> 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]
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.