快速字典查找

时间:2013-01-21 17:26:08

标签: python performance

我正在编写一些python代码,我必须检查list2中是否存在list1中的所有值,我是通过使用set(list2).difference(list1)做到的,但是功能太慢,列表中有很多项目。

所以我认为list1可能是快速查找的字典......

所以我想找到一种快速的方法来阻止列表中是否有一个不属于字典的项目

表现明智的是

之间有什么区别
d = {1: 1, 2:2, 3:3}
l = [3, 4, 5]

for n in l:
  if not n in d:
    do_stuff

VS

for n in l:
  if not d[n]:
    do_stuff

并且如果这些都是垃圾并且你知道更快的话,请告诉我。

Edit1:list1或d可以包含不在list2中但不是相反的元素。

3 个答案:

答案 0 :(得分:3)

实现目标的快捷方法是使用all和生成器理解。

s_list2 = set(list2)
all_present = all(l in s_list2 for l in list1)

在list2中不存在list1的某些元素的情况下,这将是有利的。

有些时间。如果第一个列表中的所有值都包含在第二个列表中:

In [4]: l1 = range(100)
In [5]: l2 = range(1000)
In [6]: random.shuffle(l1)
In [9]: random.shuffle(l2)
In [20]: %timeit s2 = set(l2); all(l in s2 for l in l1)
10000 loops, best of 3: 26.4 us per loop
In [21]: %timeit s1 = set(l1); s2 = set(l2); s1.issubset(s2)
10000 loops, best of 3: 25.3 us per loop

如果我们看一下第一个列表中的某些值在第二个列表中的情况:

In [2]: l1 = range(1000)
In [3]: l2 = range(100)
In [4]: random.shuffle(l1)
In [5]: random.shuffle(l2)
In [6]: sl2 = set(l2)
In [8]: %timeit ss = set(l2); set(l1) & ss == ss
10000 loops, best of 3: 27.8 us per loop
In [10]: %timeit s1 = set(l1); s2 = set(l2); s2.issubset(s1)
10000 loops, best of 3: 24.7 us per loop
In [11]: %timeit sl2 = set(l2); all(l in sl2 for l in l1)
100000 loops, best of 3: 3.58 us per loop

你可以看到这种方法在第一种情况下与issubset的性能相当,在第二种情况下更快,因为它会短路并且不需要构造2个中间集(只需要一个)

有一个大型列表和一个小型列表证明了gencomp方法的好处:

In [7]: l1 = range(10)
In [8]: l2 = range(10000)
In [9]: %timeit sl2 = set(l2); all(l in sl2 for l in l1)
1000 loops, best of 3: 230 us per loop
In [10]: %timeit sl1 = set(l1); all(l in sl1 for l in l2)
1000000 loops, best of 3: 1.45 us per loop
In [11]: %timeit s1 = set(l1); s2 = set(l2); s1.issubset(s2)
1000 loops, best of 3: 228 us per loop
In [12]: %timeit s1 = set(l1); s2 = set(l2); s2.issubset(s1)
1000 loops, best of 3: 228 us per loop

答案 1 :(得分:2)

您可以将列表转换为集合,然后使用方法issubset()检查一个是否是另一个集合的子集。

In [78]: import random

In [79]: lis2=range(100)

In [80]: random.shuffle(lis2)

In [81]: lis1=range(1000)

In [82]: random.shuffle(lis1)

In [83]: s1=set(lis1)

In [84]: all(l in s1 for l in lis2)
Out[84]: True

In [85]: %timeit all(l in s1 for l in lis2)
10000 loops, best of 3: 28.6 us per loop

In [86]: %timeit s2=set(lis2);s2.issubset(s1)
100000 loops, best of 3: 12 us per loop

In [87]: s2.issubset(s1)
Out[87]: True

答案 2 :(得分:1)

对两个列表进行排序然后一起遍历它们是O(n log n)。即:

l1.sort()
l2.sort()

j = 0
for i in range(0,len(l1)):
  while ((j < len(l2)) and (l1[i] == l2[j])):
    j = j+1
  if (j == len(l2)):
    break
  if (l1[i] > l2[j]):
    break

if (j == len(l2)): # all of l2 in l1

现在就时间复杂度来说,就像我说的那样是O(n log n)因为排序(第二个循环小于O(n))。然而,它在python中可能不比内置集合操作更快。你必须尝试一下。

[顺便说一句,如果我考虑的话,可能是一种更加灵巧的方式来完成最后一部分的理解]