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来做呢?
您可以使用集合(sets):
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']
list(set(list_2).difference(list_1))
,这避免了显式的set
转换... - Jon Clementsset() - set()
基本上是从前一个 set()
中删除任何在后一个 set()
中的值,仅保留唯一值,并将其作为字典输出? - oldboy简介:
解决方案(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)
SIDE NOTES:
(a) 解决方案2(使用自定义函数setdiff_sorted
)返回一个列表,而解决方案1返回一个数组。
(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
的默认值设置为True
会得到["f", "m", "m"]
(两个解决方案都是这样)。为什么呢?这是因为用户假设元素是唯一的。因此最好将assume_unique
保持默认值。注意,两个答案都是排序过的。
使用类似于下面这样的列表推导式:
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)
,然后使用 [item for item in list_2 if item not in set_1]
的方法生成main_list
,这样可以将每个项的检查时间从O(n)
降低到(大约)O(1)
。 - ShadowRangerenumerate()
函数:[index for (index, item) in enumerate(list_2) if item not in list_1]
。 - ettanany不确定为什么上面的解释这么复杂,当你有本地方法可用时:
main_list = list(set(list_2)-set(list_1))
如果您想要一个仅需要O(max(n, m))
的工作量来处理长度为n
和m
的输入(忽略导入)的一行解决方案,而不是O(n * m)
的工作量,则可以使用the 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
中相同索引的值匹配,你应该绝对采用Patrick's answer的方法,该方法不涉及临时的list
或set
(即使使用set
大约是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)
次对list_1
的O(n)
扫描,使其成为O(n * m)
(其中n
和m
分别是list_2
和list_1
的长度)。如果您事先将list_1
转换为set
/frozenset
,则可以在O(1)
中完成包含检查,使得总工作量与list_2
的长度成比例,即O(n)
(从技术上讲,是O(max(n, m))
,因为您需要执行O(m)
的工作来创建set
)。 - ShadowRangercrkmod_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']
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[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']
我会将这些列表 zip
在一起,以便逐个元素进行比较。
main_list = [b for a, b in zip(list1, list2) if a!= b]
从ser1中删除与ser2相同的项。
ser1 = pd.Series([1, 2, 3, 4, 5]) ser2 = pd.Series([4, 5, 6, 7, 8])
ser1[~ser1.isin(ser2)]
list_1
中没有出现过的list_2
元素或者在list_1
中与list_2
元素不在同一索引位置的元素? - Patrick Haugh