如何查找列表交集?

433
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操作(列表交集)?


10
这里的问题在于a and b的工作方式如文档中提到的那样:“表达式x and y首先评估x;如果x为false,则返回其值;否则,评估y并返回其结果值。” - Tadeck
这个回答解决了你的问题吗?如何在Python中比较两个列表并返回匹配项 - Tomerikoo
17个回答

3

这是一个例子,当你需要时,结果中的每个元素应该出现与两个数组中相同的次数。

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

2

这里的大多数解决方案并不考虑列表中元素的顺序,而是将列表视为集合。如果你想要找到同时包含在两个列表中的最长子序列之一,可以尝试以下代码。

def intersect(a, b):
    if a == [] or b == []: 
        return []
    inter_1 = intersect(a[1:], b)
    if a[0] in b:
        idx = b.index(a[0])
        inter_2 = [a[0]] + intersect(a[1:], b[idx+1:])        
        if len(inter_1) <= len(inter_2):
            return inter_2
    return inter_1

对于 a=[1,2,3]b=[3,1,4,2],此函数返回的是 [1,2] 而不是 [1,2,3]。请注意,这样的子序列并不唯一,因为对于 a=[1,2,3]b=[3,2,1][1][2][3] 都是解决方案。

2

可能有点晚了,但我觉得我应该分享一下,以防你需要手动完成(展示工作-哈哈)或者当你需要所有元素尽可能多地出现或者当你需要它是唯一的时。

请注意,还为此编写了测试。

翻译:最初的回答可能已经晚了,但我认为我应该分享一下,以防您需要手动完成(展示工作-哈哈),或者当您需要所有元素尽可能多地出现或者当您还需要它是唯一的时。请注意,还为此编写了测试。



    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)


1
如果你说的布尔 AND 是指出现在两个列表中的项目,例如交集,那么你应该看一下 Python 的 setfrozenset 类型。

1
当我们使用元组并且想要求交集时。
a=([1,2,3,4,5,20], [8,3,9,5,1,4,20])

for i in range(len(a)):

    b=set(a[i-1]).intersection(a[i])
print(b)
{1, 3, 4, 5, 20}

这个不可以直接使用 set(a[0]).intersection(*a[1:]) 来完成吗? - Jab

1

你也可以使用计数器!它不会保留顺序,但将考虑重复项:

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

1
在你的例子中,你可以直接执行 c = (d1 & d2).elements() - Juan A. Navarro

0

将列表b中每个元素的出现次数存储在字典中。然后迭代列表a,每当当前元素在字典中找到时,将其推入结果数组并将其出现次数减1。

from collections import Counter
a = [1,2,3,4,5,3]
b = [1,3,5,6,3]
res = []
b_key = Counter(b)
for i in a:
    if i in b_key and b_key[i] > 0:
        res.append(i)
        b_key[i] -= 1
    
print(res)

输出:[1, 3, 5, 3]


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接