假设我需要在迭代中收集数百万个字符串,以后我可以按位置随机索引。
我需要按顺序填充可迭代的一个项目,数百万个条目。
鉴于上述情况,原则上哪种方法可以更有效:
填充列表:
while <condition>:
if <condition>:
my_list[count] = value
count += 1
填充字典:
while <condition>:
if <condition>:
my_dict[count] = value
count += 1
(以上是pesudocode,在运行代码片段之前,所有内容都会被初始化)。
我对Python 3.4的CPython实现特别感兴趣。
答案 0 :(得分:3)
如果以正确的方式使用它们,列表肯定会更快。
In [19]: %%timeit l = []
....: for i in range(1000000): l.append(str(i))
....:
1 loops, best of 3: 182 ms per loop
In [20]: %%timeit d = {}
....: for i in range(1000000): d[i] = str(i)
....:
1 loops, best of 3: 207 ms per loop
In [21]: %timeit [str(i) for i in range(1000000)]
10 loops, best of 3: 158 ms per loop
通过理解将Python循环推向C级会给你带来相当多的时间。更喜欢将列表作为整数前缀的键更有意义。预分配可以节省更多时间:
>>> %%timeit
... l = [None] * 1000000
... for i in xrange(1000000): my_list[i] = str(i)
...
10 loops, best of 3: 147 ms per loop
为了完整性,词典理解不加快速度:
In [22]: %timeit {i: str(i) for i in range(1000000)}
1 loops, best of 3: 213 ms per loop
对于较大的字符串,我发现性能上存在非常相似的差异(尝试str(i) * 10
)。这是x86-64上的CPython 2.7.6。
答案 1 :(得分:1)
我不明白你为什么要创建一个空列表或字典,然后填充它。为什么不直接从生成过程创建新的列表或字典?
results = list(a_generator)
# Or if you really want to use a dict for some reason:
results = dict(enumerate(a_generator))
答案 2 :(得分:1)
使用map
功能可以获得更好的时间:
>>> def test1():
l = []
for i in range(10 ** 6):
l.append(str(i))
>>> def test2():
d = {}
for i in range(10 ** 6):
d[i] = str(i)
>>> def test3():
[str(i) for i in range(10 ** 6)]
>>> def test4():
{i: str(i) for i in range(10 ** 6)}
>>> def test5():
list(map(str, range(10 ** 6)))
>>> def test6():
r = range(10 ** 6)
dict(zip(r, map(str, r)))
>>> timeit.Timer('test1()', 'from __main__ import test1').timeit(100)
30.628035710889932
>>> timeit.Timer('test2()', 'from __main__ import test2').timeit(100)
31.093550469839613
>>> timeit.Timer('test3()', 'from __main__ import test3').timeit(100)
25.778271498509355
>>> timeit.Timer('test4()', 'from __main__ import test4').timeit(100)
30.10892986559668
>>> timeit.Timer('test5()', 'from __main__ import test5').timeit(100)
20.633583353028826
>>> timeit.Timer('test6()', 'from __main__ import test6').timeit(100)
28.660790917067914