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”方式不太可能是最有效的解决方案。向我们提供有关这些细节的建议将有助于解决方案旨在解决您的问题。
Matt C

Answers:


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

1
+1,但我个人使用过Frozenset,因为它是不可变的,因此可以用作字典键等
zebrabox 2010年

19
这将返回/ unique / common元素,但不会返回任何可能存在的重复元素。
Dologan

@SilentGhost。如何从两个列表中获取匹配元素的数量。在这种情况下,它是2
POKA

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

2
仅供参考。这绝对比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.MarkSilentGhost通常告诉你应该如何在一个Python化的方式来完成,但我认为从知道为什么你的解决方案不工作,你也可能受益。问题在于,一旦您在两个列表中找到第一个公共元素,就只返回该单个元素。您可以通过创建一个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

使用集合相交,集合(list1)和集合(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']
>>>
>>>

请注意,结果列表可能与原始列表的顺序不同。


谢谢您的帮助。了解我哪里出了问题以及下次应该做什么。:)
丹尼尔(Daniel)2010年

5
很好的解决方案。还有办法保留订单吗?
tarrasch

14

您可以使用简单的列表理解:

x=[1,2,3,4]
y=[3,4,5]
common = [i for i in x if i in y]
common: [3,4]

9

设置是我们可以解决此问题的另一种方法

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)

第三种方法最快,因为使用哈希表实现了集。


8

前面的答案都可以找到唯一的共同要素,但是无法解释列表中的重复项。如果希望公用元素以与列表中常见的元素相同的数字出现,则可以使用以下一线:

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

or True仅当您希望对任何元素求值时,才需要该零件False


很棒的解决方案,似乎是最彻底的,如果有点简洁
Hendeca

这应该是应该选择的答案!我假设它也适用于不相等的列表。同样,大多数解决方案都使用set不稳定的解决方案(即失去订单)。
lifebalance 2015年

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

如果运行此代码,则可以看到如果使用列表或生成器(如果迭代生成器,而不仅仅是使用它。我在强制生成器打印其长度时执行了此操作),则可获得几乎相同的性能。但是,如果使用set,则可以获得更好的性能。同样,如果您使用交集方法,您将获得更好的性能。下面列出了我计算机中每种方法的结果:

  1. 方法1:0.8150673999999999974619413478649221360683441
  2. 方法2:0.8329545000000001531148541289439890533685684
  3. 方法3:0.0016547000000000089414697868051007390022277
  4. 方法4:0.0010262999999999244948867271887138485908508

5

这是我的命题, 我认为使用set比使用for循环更容易

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

2

为什么不使用list comprehension

半线解决方案:

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

0

1)方法1将list1保存为字典,然后迭代list2中的每个elem

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)

这样做的好处是,即使使用巨大的列表或其他巨大的可迭代对象,它也将在恒定时间(几乎即时)中返回。

例如,

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
正确,它将创建一个生成器,这是一个答案。问题是要以某种方式获得这两个列表的公共元素,而此生成器会这样做。简单地重复发电机像这样:for i in common: print(i)。生成器是可迭代的,经常代替列表等其他可迭代使用。
cowlinator
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.