# I have 3 lists:
L1 = [1, 2, 3, 4, 5, 6, 7, 8, 9]
L2 = [4, 7, 8]
L3 = [5, 2, 9]
# I want to create another that is L1 minus L2's memebers and L3's memebers, so:
L4 = (L1 - L2) - L3 # Of course this isn't going to work
我想知道,做到这一点的“正确”方法是什么。我可以用很多不同的方式来做,但Python的风格指南说应该只有一种正确的方法来做每件事。我从来不知道这是什么。
答案 0 :(得分:10)
以下是一些尝试:
L4 = [ n for n in L1 if (n not in L2) and (n not in L3) ] # parens for clarity
tmpset = set( L2 + L3 )
L4 = [ n for n in L1 if n not in tmpset ]
现在我有一点时间思考,我意识到L2 + L3
事件会创建一个临时列表,立即被抛弃。所以更好的方法是:
tmpset = set(L2)
tmpset.update(L3)
L4 = [ n for n in L1 if n not in tmpset ]
更新:我看到一些关于性能的奢侈声明,我想声称我的解决方案已经尽可能快。创建中间结果,无论它们是中间列表还是中间迭代器,然后必须重复调用,总是会比简单地给L2
和L3
让集合像我一样直接迭代一样慢在这里做了。
$ python -m timeit \
-s 'L1=range(300);L2=range(30,70,2);L3=range(120,220,2)' \
'ts = set(L2); ts.update(L3); L4 = [ n for n in L1 if n not in ts ]'
10000 loops, best of 3: 39.7 usec per loop
所有其他替代方案(我能想到的)必然比这慢。例如,自己做循环而不是让set()
构造函数执行它们会增加费用:
$ python -m timeit \
-s 'L1=range(300);L2=range(30,70,2);L3=range(120,220,2)' \
'unwanted = frozenset(item for lst in (L2, L3) for item in lst); L4 = [ n for n in L1 if n not in unwanted ]'
10000 loops, best of 3: 46.4 usec per loop
使用迭代器,它们涉及的所有状态保存和回调显然会更加昂贵:
$ python -m timeit \
-s 'L1=range(300);L2=range(30,70,2);L3=range(120,220,2);from itertools import ifilterfalse, chain' \
'L4 = list(ifilterfalse(frozenset(chain(L2, L3)).__contains__, L1))'
10000 loops, best of 3: 47.1 usec per loop
所以我相信我昨晚给出的答案仍然很遥远(对于“远远超过”大约5微秒的值,显然)是最好的,除非提问者在L1
中有重复和每次重复出现在其他一个列表中时,都希望将它们删除一次。
答案 1 :(得分:6)
答案 2 :(得分:0)
假设您的个人列表不包含重复项....请使用Set
和Difference
L1 = [1, 2, 3, 4, 5, 6, 7, 8, 9]
L2 = [4, 7, 8]
L3 = [5, 2, 9]
print(list(set(L1) - set(L2) - set(L3)))
答案 3 :(得分:0)
在列表中执行此类操作可能会很快妨碍您的程序性能。每次删除都会发生什么,List操作会做一个新的malloc&移动元素。如果你有一个非常庞大的列表或其他,这可能是昂贵的。所以我建议这个 -
我假设你的清单有独特的元素。否则,您需要在dict中维护一个具有重复值的列表。无论如何,对于您提供的数据,这里是 -
方法1
d = dict()
for x in L1: d[x] = True
# Check if L2 data is in 'd'
for x in L2:
if x in d:
d[x] = False
for x in L3:
if x in d:
d[x] = False
# Finally retrieve all keys with value as True.
final_list = [x for x in d if d[x]]
方法2
如果所有看起来像太多的代码。然后你可以尝试使用set
。但是这样你的列表就会丢失所有重复的元素。
final_set = set.difference(set(L1),set(L2),set(L3))
final_list = list(final_set)
答案 4 :(得分:0)
这可能比列表理解答案更少pythonesque,但更简单:
l1 = [ ... ]
l2 = [ ... ]
diff = list(l1) # this copies the list
for element in l2:
diff.remove(element)
这里的优势在于我们保留了列表的顺序,如果有重复元素,我们每次在l2中显示只删除一个。
答案 5 :(得分:0)
我认为直觉的答案对于这样一个简单的问题来说太长了,Python已经有了一个内置函数来将两个列表链接为一个生成器。
程序如下:
itertools.chain
链接L2和L3,而不创建占用大量内存的副本x in someset
)是O(1),因此速度非常快。现在代码:
L1 = [1, 2, 3, 4, 5, 6, 7, 8, 9]
L2 = [4, 7, 8]
L3 = [5, 2, 9]
from itertools import chain
tmp = frozenset(chain(L2, L3))
L4 = [x for x in L1 if x not in tmp] # [1, 3, 6]
这应该是最快,最简单,耗电量最少的解决方案之一。