【问题标题】:search times of "x in []" vs "x in {}"“x in []”与“x in {}”的搜索时间
【发布时间】:2012-06-04 13:15:22
【问题描述】:

我遇到了一个问题,我必须通过代理日志查看用户是否访问过网站列表。

我编写了一个小脚本来读取所有代理日志,将访问的主机与列表进行匹配:

for proxyfile in proxyfiles:
    for line in proxyfile.readlines():
        if line[4] in hosts_list:
            print line

hosts_file 很大,我们正在讨论大约 10000 个主机,我注意到搜索花费的时间比预期的要长。

我写了一个小测试:

import random, time
test_list = [x for x in range(10000)]
test_dict = dict(zip(test_list, [True for x in range(10000)]))

def test(test_obj):
 s_time = time.time()
 for i in range(10000):
  random.randint(0,10000) in test_obj
 d_time = time.time() - s_time
 return d_time

print "list:", test(test_list)
print "dict:",test(test_dict)

结果如下:

list: 5.58524107933
dict: 0.195574045181

所以,我的问题。 是否可以以更方便的方式执行此搜索?创建列表的字典似乎是一种 hack,因为我想搜索它们的键而不是它包含的值。

【问题讨论】:

  • 在测试代码的 sn-ps 时,您可以使用 timeit module 而不是自己制作。 (如果你使用 ipython 会更容易。)
  • 您需要在时间观察中包含 generating dict。
  • 你可以使用集合。
  • @Martijn Pieters,list->dict 转换只进行一次,之后使用了数百万次。一遍又一遍地创建字典是不现实的。
  • 您可以使用dict.fromkeys(test_list, True),或者在这种情况下使用set,而不是dict(zip(test_list, [True for x in range(10000)]))

标签: python search optimization python-2.2


【解决方案1】:

“因为我想搜索它们的键而不是它包含的值” => 然后只需使用 set

【讨论】:

  • 好主意,不幸的是在这种情况下我绑定到 python 2.2。但是,我同意使用 set() 是一个可行的解决方案
  • 集合的底层实现基本上是一个只有键而没有值的字典。在 Python 2.2 上,只需使用字典即可​​。
  • 在 ActiveState 中搜索旧的设置配方。有几个。
【解决方案2】:

我同意你应该为这样的事情使用字典,在更新的 python 上设置,如果你的应用程序可能的话,考虑迁移到比 2.2 更新的 python。

但是,如果您的列表已排序,您可以使用 bisect 模块快速搜索列表以查找元素。没有字典那么快,但非常接近。

import random, time
import bisect

class BisectContainsList(list):
    def __contains__(self, elem):
        i = bisect.bisect_left(self, elem)
        if i != len(self) and self[i] == elem:
            return True
        return False

test_list = [x for x in range(10000)]
test_dict = dict(zip(test_list, [True for x in range(10000)]))
test_blist = BisectContainsList(test_list)

def test(test_obj):
 s_time = time.time()
 for i in range(10000):
  random.randint(0,10000) in test_obj
 d_time = time.time() - s_time
 return d_time

print "list:", test(test_list)
print "dict:", test(test_dict)
print "blist", test(test_blist)

对于(在 2.7 上测试):

list: 1.19566082954
dict: 0.0248260498047
blist 0.0598628520966

【讨论】:

    【解决方案3】:

    如果您的列表已排序,您可以将 bisect 模块与此帮助函数一起使用:

    def sorted_list_contains(alist, item):
        i = bisect.bisect_left(alist, item)
        return i != len(alist) and alist[i] == item
    

    编辑:当我发布此内容时,我没有看到 Matt Anderson 使用 bisect 的答案。我将把它留作替代实现。

    【讨论】:

      猜你喜欢
      • 2012-09-25
      • 2011-03-29
      • 1970-01-01
      • 2017-12-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多