Python 如何获取列表中不包含在另一个列表中的n个元素?

Python 如何获取列表中不包含在另一个列表中的n个元素?,python,Python,我有两个不同大小的列表(其中一个可以比另一个大),带有一些公共元素。我想从第一个列表中获取不在第二个列表中的n元素 我看到了两个解决方案系列(下面的示例适用于n=3) 它们都是正确的,输出是正确的 [9, 3, 5] [3, 5, 7] [3, 5, 7] (第一个解决方案没有给出前3个,因为set没有保留顺序-但在我的情况下,这是可以的,因为我仍然会有未排序(甚至显式洗牌)的列表) 是否有最具蟒蛇风格和合理的最佳方案 解决方案1首先计算差异,然后切片-我发现这非常低效(我的列表的大小将是~1

我有两个不同大小的列表(其中一个可以比另一个大),带有一些公共元素。我想从第一个列表中获取不在第二个列表中的
n
元素

我看到了两个解决方案系列(下面的示例适用于
n=3

它们都是正确的,输出是正确的

[9, 3, 5]
[3, 5, 7]
[3, 5, 7]
(第一个解决方案没有给出前3个,因为
set
没有保留顺序-但在我的情况下,这是可以的,因为我仍然会有未排序(甚至显式洗牌)的列表)

是否有最具蟒蛇风格和合理的最佳方案

解决方案1首先计算差异,然后切片-我发现这非常低效(我的列表的大小将是~100k个元素,我将寻找前100个)

解决方案2看起来更优化,但它很难看(这是一个品味问题,但我了解到,当Python中的某些东西看起来难看时,这意味着通常会有更多的Python解决方案)


如果没有更好的替代方案,我会选择解决方案2。

我会使用set.difference和slice:

print(list(set(a).difference(b))[:3])
[3, 5, 7]
set.difference已经为您提供了a中不在b中的元素:

set([3, 5, 7, 9])
所以你只需要一片

或在集合中没有调用列表时使用iter、next和理解:

diff = iter(set(a).difference(b))
n = 3
sli = [next(diff) for _ in range(n)]
print(sli)
.差异不会创建第二个集合,因此它是一个更有效的解决方案:

In [1]: a = [i for i in range(2, 10000000)]  
In [2]: b = [i * 2 for i in range (1, 10000000)]   
In [3]: timeit set(a).difference(b)
1 loops, best of 3: 848 ms per loop    
In [4]: timeit set(a)- set(b)
1 loops, best of 3: 1.54 s per loop
对于上面的大型列表,
s2=[i For i in a if i not in b]
会给你足够的时间在吃完之前做饭

使用国际热核聚变实验堆和。区别:

In [11]: %%timeit                                
diff = iter(set(a).difference(b))
n = 3
sli = [next(diff) for _ in range(n)]
   ....: 
1 loops, best of 3: 797 ms per loop

可以将b转换为集合,但不能转换为a。设置生成器以利用惰性,然后使用理解来获取所需的项目:

a = [i for i in range(2, 10)]
b = [i * 2 for i in range (1, 10)]
bset = set(b)
agen = (i for i in a if not i in set(b))
first3 = [j for (i,j) in enumerate(agen) if i < 3]
print(first3)
a=[i代表范围(2,10)中的i]
b=[i*2表示范围(1,10)内的i]
b设置=设置(b)
agen=(如果集合(b)中没有i,则a中的i代表i)
first3=[j表示枚举(agen)中的(i,j),如果i<3]
打印(前3页)

如果您只需要100,那么避免构建完全差异可能会稍微快一点,但具体速度取决于您的数据集

import random
from itertools import islice

def m1(a,b):
    return list(set(a) - set(b))[:100]
def m2(a,b):
    return list(set(a).difference(b))[:100] 
def m3(a,b):
    return list(islice(set(a).difference(b), 100))
def m4(a,b):
    bset = set(b)
    return list(islice((x for x in a if x not in bset), 100))
给我

>>> a = [random.randint(0, 10**6) for i in range(10**5)]
>>> b = [random.randint(0, 10**6) for i in range(10**5)]
>>> %timeit m1(a,b)
10 loops, best of 3: 121 ms per loop
>>> %timeit m2(a,b)
10 loops, best of 3: 98.7 ms per loop
>>> %timeit m3(a,b)
10 loops, best of 3: 82.3 ms per loop
>>> %timeit m4(a,b)
10 loops, best of 3: 42.8 ms per loop
>>> 
>>> a = list(range(10**5))
>>> b = [i*2 for i in a]
>>> %timeit m1(a,b)
10 loops, best of 3: 58.7 ms per loop
>>> %timeit m2(a,b)
10 loops, best of 3: 50.8 ms per loop
>>> %timeit m3(a,b)
10 loops, best of 3: 40.7 ms per loop
>>> %timeit m4(a,b)
10 loops, best of 3: 21.7 ms per loop

只要多做一点工作,您甚至可以避免制作完整的
bset
。例如,如果你只看列表中的前10^4左右,很可能会发现100人失踪,那么首先尝试一下可能是值得的。但是,如果这成为代码中的瓶颈,我会感到惊讶,因此可能不值得担心。

它比我的
列表(set(a)-set(b))
好吗?(从效率的角度来看,尤其是对于大型列表)@WoJ,是的,它更有效,我添加了一些计时显示iter和列表组件堆栈?@padraiccnningham:看起来与列表-列表组合相当。
>>> a = [random.randint(0, 10**6) for i in range(10**5)]
>>> b = [random.randint(0, 10**6) for i in range(10**5)]
>>> %timeit m1(a,b)
10 loops, best of 3: 121 ms per loop
>>> %timeit m2(a,b)
10 loops, best of 3: 98.7 ms per loop
>>> %timeit m3(a,b)
10 loops, best of 3: 82.3 ms per loop
>>> %timeit m4(a,b)
10 loops, best of 3: 42.8 ms per loop
>>> 
>>> a = list(range(10**5))
>>> b = [i*2 for i in a]
>>> %timeit m1(a,b)
10 loops, best of 3: 58.7 ms per loop
>>> %timeit m2(a,b)
10 loops, best of 3: 50.8 ms per loop
>>> %timeit m3(a,b)
10 loops, best of 3: 40.7 ms per loop
>>> %timeit m4(a,b)
10 loops, best of 3: 21.7 ms per loop