性能比较:插入vs构建Python集合操作

时间:2011-04-29 18:07:34

标签: python set time-complexity

在python中,它更快 a)从n个项目列表中构建一个集合 b)将n个项目插入一组?

我找到了这个页面(http://wiki.python.org/moin/TimeComplexity),但它没有足够的信息来推断哪个更快。

看来,一次插入一个项目可能在最坏的情况下需要O(n * n)时间(假设它使用dicts),并且在一般情况下需要O(n * 1)。初始化带有列表的集合是否可以提高性能?

4 个答案:

答案 0 :(得分:19)

O()复杂性而言 - 它肯定是相同的,因为两种方法完全相同 - 将n项插入集合中。

差异来自实现:从iterable初始化的一个明显优势是你可以保存很多Python级函数调用 - 迭代的初始化完全在C级(**)完成。

实际上,对5,000,000个随机整数列表的一些测试表明,逐个添加的速度较慢:

lst = [random.random() for i in xrange(5000000)]
set1 = set(lst)    # takes 2.4 seconds

set2 = set()       # takes 3.37 seconds
for item in lst:
    set2.add(item)

(**)查看集合代码(Objects/setobject.c),最终项目插入归结为对set_add_key的调用。从iterable初始化时,在紧C循环中调用此函数:

while ((key = PyIter_Next(it)) != NULL) {
  if (set_add_key(so, key) == -1) {
    Py_DECREF(it);
    Py_DECREF(key);
    return -1;
  } 
  Py_DECREF(key);
}

另一方面,每次调用set.add都会调用属性查找,该属性查找解析为C set_add函数,后者又调用set_add_key。由于项目添加本身相对较快(Python的哈希表实现非常高效),所以这些额外的调用都会建立起来。

答案 1 :(得分:2)

$ python -V
Python 2.5.2
$ python -m timeit -s "l = range(1000)" "set(l)"
10000 loops, best of 3: 64.6 usec per loop
$ python -m timeit -s "l = range(1000)" "s = set()" "for i in l:s.add(i)"
1000 loops, best of 3: 307 usec per loop

答案 2 :(得分:0)

以下是使用timeit运行比较的结果。似乎使用list的set初始化更快,很想知道为什么会这样:

from timeit import timeit
timeit("set(a)","a=range(10)")
# 0.9944498532640864

timeit("for i in a:x.add(i)","a=range(10);x=set()")
# 1.6878826778265648

Python版本:2.7

答案 3 :(得分:0)

在我的Thinkpad上:

In [37]: timeit.timeit('for a in x: y.add(a)',
                       'y=set(); x=range(10000)', number=10000)
Out[37]: 12.18006706237793

In [38]: timeit.timeit('y=set(x)', 'y=set(); x=range(10000)', number=10000)
Out[38]: 3.8137960433959961