如何比较python中的两个列表并返回匹配项


379

我想获取两个列表并查找两个列表中都出现的值。

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

returnMatches(a, b)

[5]例如,将返回。


4
以下所有答案对我来说似乎都是错误的。如果在两个列表中重复一个数字会发生什么,您肯定想知道(?)(例如,说两个列表都有两次“ 5”)。任何使用集合的解决方案都会立即删除所有重复的项,并且您会输掉该信息。
MH

Answers:


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 2012年

24
另一个注意事项:列表推导找到在两个相同位置上出现的值(这就是SilentGhost的“顺序很重要”的意思)。设置的相交解决方案还将在不同位置找到匹配项。这些是对2个完全不同的问题的解答...(操作员的问题对于它的询问是模棱两可的)
drevicko

如果您的列表是列表列表,例如a = [[[0,0],[1,0]]和b = [[2,3],[0,0]]
Schneems

3
第一个示例的时间复杂度是set(a) & set(b)多少?
AdjunctProfessorFalcon's

请注意,如果两个集合都为空并且您希望比较通过,则此方法不起作用。因此更改为“((set(a)和set(b))或(not a and not b))”
尼尔·麦吉尔

395

使用set.intersection(),它快速且可读。

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

28
该答案具有良好的算法性能,因为只有一个列表(应首选较短的列表)被转换为一个集合以进行快速查找,而遍历另一个列表以查找该集合中的项目。
u0b34a0f6ae

18
bool(set(a).intersection(b))TrueFalse
阿克沙伊

6
由于人们可能需要difference或,因此该答案更灵活,更易读union
张世和

如果我有对象作为列表元素并且只希望部分匹配,即只有某些属性必须匹配才能被视为匹配对象,该怎么办?
CGFoX

.intersection()vs 是否有任何性能差异&
布兰登银行

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()答案至少与其他解决方案一样快,并且也是最易读的,因此它应该是解决此常见问题的标准解决方案。


Set实际上是在消除重复,所以在我的情况下不会起作用
rgralma

@rgralma set从现有的文件中复制新文件list不会删除原始文件中的任何内容list。如果您想要特殊的逻辑来处理列表中的重复项,我认为您需要提出一个新问题,因为答案将需要特定于您希望如何处理重复项。
Joshmaker

67

我更喜欢基于集合的答案,但这还是可行的

[x for x in a if x in b]



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
接受的答案不适用于包含字符串的列表。这一个。
安东尼

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
亚伦牛顿

5

检查对象的深度为1且保持顺序的列表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 

尽管此代码可以回答问题,但提供有关如何和/或为什么解决问题的其他上下文将提高​​答案的长期价值。
唐老鸭

4

也可以使用itertools.product。

>>> common_elements=[]
>>> for i in list(itertools.product(a,b)):
...     if i[0] == i[1]:
...         common_elements.append(i[0])

3

您可以使用

def returnMatches(a,b):
       return list(set(a) & set(b))


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 '19

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

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。可能不是明智的表现。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.