关于性能:Python集与列表

Python Sets vs Lists

在Python中,哪种数据结构更高效/更快?假设这个顺序对我来说并不重要,而且无论如何我都要检查重复项,那么Python设置是否比Python列表慢?


这取决于你打算用它做什么。

集合在确定对象是否存在于集合中时(如x in s中),速度要快得多,但在迭代其内容时,速度要慢于列表。

您可以使用Timeit模块查看您的情况下哪个更快。


当您只想遍历值时,列表比集合稍快。

但是,如果要检查项是否包含在列表中,则集合比列表快得多。但它们只能包含唯一的项。

事实证明,元组的执行方式与列表几乎完全相同,除了它们的不变性。

迭代

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
>>> def iter_test(iterable):
...     for i in iterable:
...         pass
...
>>> from timeit import timeit
>>> timeit(
...    "iter_test(iterable)",
...     setup="from __main__ import iter_test; iterable = set(range(10000))",
...     number=100000)
12.666952133178711
>>> timeit(
...    "iter_test(iterable)",
...     setup="from __main__ import iter_test; iterable = list(range(10000))",
...     number=100000)
9.917098999023438
>>> timeit(
...    "iter_test(iterable)",
...     setup="from __main__ import iter_test; iterable = tuple(range(10000))",
...     number=100000)
9.865639209747314

确定对象是否存在

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
>>> def in_test(iterable):
...     for i in range(1000):
...         if i in iterable:
...             pass
...
>>> from timeit import timeit
>>> timeit(
...    "in_test(iterable)",
...     setup="from __main__ import in_test; iterable = set(range(1000))",
...     number=10000)
0.5591847896575928
>>> timeit(
...    "in_test(iterable)",
...     setup="from __main__ import in_test; iterable = list(range(1000))",
...     number=10000)
50.18339991569519
>>> timeit(
...    "in_test(iterable)",
...     setup="from __main__ import in_test; iterable = tuple(range(1000))",
...     number=10000)
51.597304821014404


列表性能:

1
2
3
>>> import timeit
>>> timeit.timeit(stmt='10**6 in a', setup='a = range(10**6)', number=100000)
0.008128150348026608

设置性能:

1
2
>>> timeit.timeit(stmt='10**6 in a', setup='a = set(range(10**6))', number=100000)
0.005674857488571661

可能需要考虑元组,因为它们与列表类似,但不能修改。它们占用的内存略少,访问速度更快。它们没有清单那么灵活,但比清单更有效率。它们通常用作字典键。

集合也是序列结构,但与列表和元组有两个区别。尽管集合确实有一个顺序,但是这个顺序是任意的,不受程序员的控制。第二个区别是集合中的元素必须是唯一的。

定义为set。[Python维基]。

1
2
3
>>> x = set([1, 1, 2, 2, 3, 3])
>>> x
{1, 2, 3}


set由于近即时的"包含"检查而获胜:https://en.wikipedia.org/wiki/hash_table

列表实现:通常是一个数组,级别较低,靠近金属,便于迭代和按元素索引随机访问。

set实现:https://en.wikipedia.org/wiki/hash_table,它不在列表上迭代,而是通过从键计算哈希来查找元素,因此它取决于键元素的性质和哈希函数。类似于dict的用法。我怀疑如果元素很少(<5),list可能更快,元素计数越大,set对包含检查的执行效果越好。对元素的添加和去除也很快。

注:如果已对list进行排序,则搜索list的速度可能相当快,但在通常情况下,set对包含检查的速度更快、更简单。


我建议在用例被限制为引用或搜索存在的情况下使用集合实现,在用例要求您执行迭代的情况下使用元组实现。列表是一种低级实现,需要大量的内存开销。