我有两个不同大小的列表(一个可以比另一个大),有一些共同的元素。我想从第一个列表中获取n
个不在第二个列表中的元素。
我看到两个解决方案系列(以下示例适用于n=3
)
a = [i for i in range(2, 10)]
b = [i * 2 for i in range (1, 10)]
# [2, 3, 4, 5, 6, 7, 8, 9] [2, 4, 6, 8, 10, 12, 14, 16, 18]
# solution 1: generate the whole list, then slice
s1 = list(set(a) - set(b))
s2 = [i for i in a if i not in b]
for i in [s1, s2]:
print (i[:3])
# solution 2: the simple loop solution
c = 0
s3 = []
for i in a:
if i not in b:
s3.append(i)
c += 1
if c == 3:
break
print(s3)
所有这些都是正确的,输出是
[9, 3, 5]
[3, 5, 7]
[3, 5, 7]
(第一个解决方案没有给出第一个 3个,因为set
不保留顺序 - 但在我的情况下这是可以的,因为我将没有排序(甚至明确洗牌)无论如何列出)
是否有最pythonic和最合理的?
解决方案1首先计算差异,然后是切片 - 我发现效率非常低(我的列表大小将是~100k元素,我将寻找前100个)。
解决方案2看起来更优,但它很丑陋(这是一个品味的问题,但我了解到,当Python中的某些东西看起来很丑陋时,它意味着通常有更多的pythonic解决方案)。
如果没有更好的选择,我会解决问题2。
答案 0 :(得分:5)
我会使用set.difference和slice:
print(list(set(a).difference(b))[:3])
[3, 5, 7]
set.difference已经为你提供了不在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)
.difference不会创建第二个集合,因此它是一个更有效的解决方案:
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]
以上的大型清单,会给你足够的时间在吃完之前做饭。
使用iter和.difference:
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
答案 1 :(得分:2)
如果您只需要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
通过更多工作,您甚至可以避免需要完整document.getElementById("container").appendChild(document.createTextNode('\ue145'))
。例如,如果你只查看列表的前10 ^ 4左右,你很可能会发现100个丢失,那么首先尝试它可能是值得的。但是,如果这在您的代码中成为瓶颈,我会感到惊讶,所以它可能不值得担心。
答案 2 :(得分:0)
可以将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)