Python会在一个列表中找到不在另一个列表中的元素

我需要比较两个列表,以便创建一个在一个列表中找到而在另一个列表中没有的特定元素的新列表。例如:

main_list=[]
list_1=["a", "b", "c", "d", "e"]
list_2=["a", "f", "c", "m"]

我想循环遍历list_1,并将list_2中没有在list_1中找到的所有元素附加到main_list。

结果应该是:

main_list=["f", "m"]

我怎么用python来做呢?

373739 次浏览

我将zip列表放在一起,逐个元素比较它们。

main_list = [b for a, b in zip(list1, list2) if a!= b]

你可以使用集合:

main_list = list(set(list_2) - set(list_1))

输出:

>>> list_1=["a", "b", "c", "d", "e"]
>>> list_2=["a", "f", "c", "m"]
>>> set(list_2) - set(list_1)
set(['m', 'f'])
>>> list(set(list_2) - set(list_1))
['m', 'f']

根据@JonClements的评论,这里是一个更整洁的版本:

>>> list_1=["a", "b", "c", "d", "e"]
>>> list_2=["a", "f", "c", "m"]
>>> list(set(list_2).difference(list_1))
['m', 'f']

像这样使用列表理解:

main_list = [item for item in list_2 if item not in list_1]

输出:

>>> list_1 = ["a", "b", "c", "d", "e"]
>>> list_2 = ["a", "f", "c", "m"]
>>>
>>> main_list = [item for item in list_2 if item not in list_1]
>>> main_list
['f', 'm']

编辑:

就像下面评论中提到的,对于大列表,上面不是理想的解决方案。在这种情况下,更好的选择是先将list_1转换为set:

set_1 = set(list_1)  # this reduces the lookup time from O(n) to O(1)
main_list = [item for item in list_2 if item not in set_1]
main_list=[]
list_1=["a", "b", "c", "d", "e"]
list_2=["a", "f", "c", "m"]


for i in list_2:
if i not in list_1:
main_list.append(i)


print(main_list)

输出:

['f', 'm']

如果要考虑出现的次数,你可能需要使用类似collections.Counter的东西:

list_1=["a", "b", "c", "d", "e"]
list_2=["a", "f", "c", "m"]
from collections import Counter
cnt1 = Counter(list_1)
cnt2 = Counter(list_2)
final = [key for key, counts in cnt2.items() if cnt1[key] != counts]


>>> final
['f', 'm']

正如承诺的那样,这也可以处理不同数量的事件,如“差异”:

list_1=["a", "b", "c", "d", "e", 'a']
cnt1 = Counter(list_1)
cnt2 = Counter(list_2)
final = [key for key, counts in cnt2.items() if cnt1[key] != counts]


>>> final
['a', 'f', 'm']

如果你想要一个单行解决方案(忽略导入),它只需要O(max(n, m))工作来处理长度为nm的输入,而不需要O(n * m)工作,你可以使用itertools模块:

from itertools import filterfalse


main_list = list(filterfalse(set(list_1).__contains__, list_2))

这利用了函数函数在构造时接受回调函数的优点,允许它创建一次回调并为每个元素重用它,而不需要将它存储在某个地方(因为filterfalse将它存储在内部);列表推导式和生成器表达式可以做到这一点,但它很难看

在一行中得到相同的结果:

main_list = [x for x in list_2 if x not in list_1]

速度:

set_1 = set(list_1)
main_list = [x for x in list_2 if x not in set_1]

当然,如果比较的目的是位置,那么:

list_1 = [1, 2, 3]
list_2 = [2, 3, 4]

应该生产:

main_list = [2, 3, 4]

(因为list_2中没有值在list_1中的同一索引处匹配),你肯定应该使用帕特里克的回答,它不涉及临时的__abc2或__abc3(即使__abc3大致是O(1),它们具有更高的“常量”;如果你的问题是位置敏感的,则当匹配元素出现在不匹配的偏移时,它是唯一的正确的解决方案。

†:将列表理解作为一行程序来做同样的事情的方法是滥用嵌套循环来创建和缓存值在"外层"循环,例如:

main_list = [x for set_1 in (set(list_1),) for x in list_2 if x not in set_1]

这也在Python 3上带来了轻微的性能优势(因为现在set_1在理解代码中是局部作用域,而不是从每次检查的嵌套作用域中查找;在Python 2上,这并不重要,因为Python 2不使用闭包进行列表推导;它们在相同的范围内运行)。

< p > TL;博士: < br > 解决方案(1)< / >强

import numpy as np
main_list = np.setdiff1d(list_2,list_1)
# yields the elements in `list_2` that are NOT in `list_1`

解决方案(2) 你想要一个排序的列表

def setdiff_sorted(array1,array2,assume_unique=False):
ans = np.setdiff1d(array1,array2,assume_unique).tolist()
if assume_unique:
return sorted(ans)
return ans
main_list = setdiff_sorted(list_2,list_1)

< br > < br >


< p > 解释: < br > (1) < / >强你可以使用NumPy setdiff1d (array1array2 assume_unique = False)。

assume_unique询问用户数组是否已经是唯一的。
如果False,则首先确定唯一元素。< br > 如果True,函数将假定元素已经是唯一的,并且函数将跳过确定唯一元素

这将在array1中产生array2中的唯一值。assume_unique默认为False

如果你关心的是独特的元素(基于Chinny84的回应),那么只需使用(其中assume_unique=False =>为默认值):

import numpy as np
list_1 = ["a", "b", "c", "d", "e"]
list_2 = ["a", "f", "c", "m"]
main_list = np.setdiff1d(list_2,list_1)
# yields the elements in `list_2` that are NOT in `list_1`
< p > < br > (2) 对于那些想要对答案进行排序的人,我已经做了一个自定义函数:

import numpy as np
def setdiff_sorted(array1,array2,assume_unique=False):
ans = np.setdiff1d(array1,array2,assume_unique).tolist()
if assume_unique:
return sorted(ans)
return ans

要得到答案,运行:

main_list = setdiff_sorted(list_2,list_1)

< p > 边注: < br > (a)方案2(自定义函数setdiff_sorted)返回< em > < / em >列表(与方案1中的< em > < / em >数组相比)。

(b)如果你不确定元素是否唯一,只需在解决方案A和b中使用NumPy的setdiff1d的默认设置。参见注(c)。

(c)如果两个列表中的任何一个是唯一的,情况将有所不同。
list_2不是唯一的:list2 = ["a", "f", "c", "m", "m"]list1保持原样:list_1 = ["a", "b", "c", "d", "e"]
设置assume_unique的默认值会产生["f", "m"](在两种解决方案中)。然而,如果你设置assume_unique=True,两个解决方案都会给出["f", "m", "m"]。为什么?这是因为用户假设元素是唯一的)。因此,最好保留assume_unique的默认值。注意,两个答案都是排序的。

当你有本地方法可用时,不确定为什么上面的解释如此复杂:

main_list = list(set(list_2)-set(list_1))

从ser1中删除ser2中的条目。

输入

ser1 = pd。级数([1,2,3,4,5]) Ser2 = pd。Series([4,5,6,7,8])

解决方案

ser1 [~ ser1.isin (ser2)]

我用了两种方法,我发现其中一种方法比另一种更有用。以下是我的回答:

我的输入数据:

crkmod_mpp = ['M13','M18','M19','M24']
testmod_mpp = ['M13','M14','M15','M16','M17','M18','M19','M20','M21','M22','M23','M24']

我喜欢这种方法,因为它保留了位置

test= list(np.setdiff1d(testmod_mpp,crkmod_mpp))
print(test)
['M15', 'M16', 'M22', 'M23', 'M20', 'M14', 'M17', 'M21']

Method2:虽然答案和Method1一样,但是打乱了顺序

test = list(set(testmod_mpp).difference(set(crkmod_mpp)))
print(test)
['POA23', 'POA15', 'POA17', 'POA16', 'POA22', 'POA18', 'POA24', 'POA21']

Method1 np.setdiff1d完全符合我的要求。 这是信息的答案。< / p >