Answers:
TL; DR:
解决方案(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)
说明:
(1)可以使用与NumPy的setdiff1d
(array1
,array2
,assume_unique
= False
)。
assume_unique
询问用户数组是否已经唯一。
如果为False
,则首先确定唯一元素。
如果为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`
(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)
旁注:
(a)解决方案2(自定义函数setdiff_sorted
)返回一个列表(与解决方案1中的数组相比)。
(b)如果不确定这些元素是否唯一,则只需setdiff1d
在解决方案A和B中都使用NumPy的默认设置。并发症的例子是什么?见注释(c)。
(c)如果两个列表中的任何一个都不唯一,情况将有所不同。
说list_2
的不是唯一的:list2 = ["a", "f", "c", "m", "m"]
。保持list1
原样:list_1 = ["a", "b", "c", "d", "e"]
设置assume_unique
yields 的默认值["f", "m"]
(在两种解决方案中)。但是,如果您设置了assume_unique=True
,两种解决方案都可以["f", "m", "m"]
。为什么?这是因为用户认为元素是唯一的)。因此,最好保持assume_unique
为其默认值。请注意,两个答案均已排序。
您可以使用集:
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']
unique
元素,那么这很好,但是如果我们有多个元素,那m's
该怎么办呢?
list(set(list_2).difference(list_1))
来避免显式set
转换...
使用这样的列表理解:
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]
list_1
,您需要预转换为set
/ frozenset
,例如set_1 = frozenset(list_1)
,然后main_list = [item for item in list_2 if item not in set_1]
将检查时间从O(n)
每个项目减少到(大约)O(1)
。
enumerate()
它:[index for (index, item) in enumerate(list_2) if item not in list_1]
如果您想要一种单线解决方案(忽略导入),该解决方案仅需要O(max(n, m))
长度n
和长度输入工作,m
而不需要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]
(因为in list_2
中的值与in 中的相同索引相匹配list_1
),您绝对应该使用Patrick的答案,该答案不涉及临时list
s或set
s(即使set
s大致相同O(1)
,它们每张支票的“常数”因数也比简单的等式支票高) )并且涉及O(min(n, m))
工作,比其他任何答案都要少,并且如果您的问题对位置敏感,则是唯一正确的答案当匹配元素以不匹配的偏移量出现时解决方案。
†:使用列表理解来做与单行代码相同的方法是滥用嵌套循环以在“最外层”循环中创建和缓存值,例如:
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并未使用闭包列出理解;它们的作用范围与所使用的作用域相同)。
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']
list_1
是大,list_2
是不平凡的大小,因为它涉及到len(list_2)
O(n)
的扫描list_1
,使它O(n * m)
(其中n
和m
是的长度list_2
和list_1
分别)。如果您转换list_1
成set
/ frozenset
,则可以在中进行contains的检查O(1)
,使总工作量O(n)
为list_2
(技术上为O(max(n, m))
,因为您确实O(m)
做了set
)。
我会将zip
这些列表放在一起,以逐个元素比较它们。
main_list = [b for a, b in zip(list1, list2) if a!= b]
list
s 的一次廉价传递,并且list
正在构造一个新的,而没有其他临时对象,没有昂贵的遏制检查等
我使用了两种方法,发现一种方法比其他方法有用。这是我的答案:
我的输入数据:
crkmod_mpp = ['M13','M18','M19','M24']
testmod_mpp = ['M13','M14','M15','M16','M17','M18','M19','M20','M21','M22','M23','M24']
方法1:np.setdiff1d
我喜欢这种方法,因为它保留了位置
test= list(np.setdiff1d(testmod_mpp,crkmod_mpp))
print(test)
['M15', 'M16', 'M22', 'M23', 'M20', 'M14', 'M17', 'M21']
方法2:尽管给出的答案与方法1相同,但扰乱了顺序
test = list(set(testmod_mpp).difference(set(crkmod_mpp)))
print(test)
['POA23', 'POA15', 'POA17', 'POA16', 'POA22', 'POA18', 'POA24', 'POA21']
方法1完全np.setdiff1d
符合我的要求。此答案仅供参考。
如果应该考虑发生的次数,则可能需要使用类似以下内容的方法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.get(key, 0) != 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.get(key, 0) != counts]
>>> final
['a', 'f', 'm']
list_2
没有出现的list_1
元素或list_2
中没有出现在相同索引处的元素list_1
?