在Python中获取两个列表的差异

15

我有两个列表,l1l2。 我需要从l1中获取不在l2中的项目。

l1 = [2, 3, 4, 5]
l2 = [0, 1, 2, 3]

我想要获取[l1]中只有[4,5]这两个新值。

[i for i in l1 if not i in l2 ]

我可以不用迭代来实现吗?


1
听起来像是过早地优化了。如果这本质上是一个迭代问题,为什么你说“没有迭代”呢? - the wolf
10个回答

17

简短回答是: list(set(l1) - set(l2)),但这不会保留原有的顺序。

详细来说,不完全是,因为CPU内部总是要进行迭代。不过如果你使用set(),迭代将会被高度优化,并且比列表推导式快得多(更不用说在集合中使用value in list来检查成员资格比在列表中快得)。


有人告诉我,内联迭代也是高度优化的。当它执行时,与“for i in l1: do()”不同。 - Pol
列表推导式(而不是内联迭代)确实比for循环更优化,但集合差异可能是用高速C语言完成的,这将更好。并且,由于您正在使用集合,因此“in”关键字(或其C表兄弟)非常快,从而进一步提高了速度。 - orlp

12

你不能不迭代地完成它。即使你调用单个方法,内部也会进行迭代。

你的方法对于小列表来说是可以的,但是对于大列表,你可以使用这种方法代替:

s2 = set(l2)
result = [i for i in l1 if not i in s2 ]

这将会很快,同时也会保留l1中元素的原始顺序。


3
如果您不关心元素的顺序,可以使用集合(sets):
l1 = set([2, 3, 4, 5])
l2 = set([0, 1, 2, 3])
print l1 - l2

打印

set([4, 5])

是的,我也试图做类似的事情。但是没有成功。现在没问题了。谢谢。 - Pol

2
转换成集合适用于列表元素可以转换为集合的情况。否则,您需要像Mark Byers的解决方案这样的东西。如果您有大型列表需要比较,则可能不想付出内存分配开销,并将其简化为以下行:
[l1.remove(m) for m in l1 if m in l2]

欢迎来到SO。也许您应该重新考虑您的答案,因为OP似乎想要一个无迭代的解决方案。我猜他的意思是即使作为列表推导,也不要使用for循环。因此,使用map或filter解决方案可能更合适。另外,我认为他不想改变原始列表。 - Don Question

1

你可以使用 set_1.difference_update(set_2) 来进行原地差异操作:

>>sl1 = set([2, 3, 4, 5])
>>sl2 = set([0, 1, 2, 3])
>>sl1.difference_update(sl2)
>>sl1
set([4, 5])

1
您可以简单地按照以下步骤完成:
list( set(l1) - set(l2) )

这应该可以解决问题。


0

将它们转换为集合并使用差异运算符:

l1=[2,3,4,5]
l2=[0,1,2,3]

answer = set(l1) - set(l2)

0

使用内置模块set

>>> a = set([1,2,3,4,5])
>>> b = set([1,3,5])
>>> a.difference(b)
set([2, 4])

另一种方法

>>> a = set([1,2,3,4,5])
>>> b = [1,3,5]
>>> a.difference(b)
set([2, 4])

0

就像编程一样,一个简单的任务可以用多种方式完成。 我们可以使用列表推导式这样的方法来解决完全相同的问题。

fruits = ["apple", "banana", "cherry", "kiwi", "mango"]
ddd = ["apple", "banana", "mango"]

newlist = [x for x in fruits if x not in ddd]

print(newlist)

-1

例子:

>>a = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
>>b = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]

我们也可以通过连接来获得完整的差异:

>>list (set(a) -set(b)) +  list (set(b) -set(a))
>>[89, 34, 21, 55, 4, 6, 7, 9, 10, 11, 12]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接