快速迭代python中可迭代(不是列表)的前n项

时间:2010-04-23 21:47:09

标签: iterator performance python generator

我正在寻找一种pythonic方法来迭代迭代的第一个n项( upd :在常见情况下不是列表,因为列表事情是微不足道的),尽可能快地做到这一点非常重要。这就是我现在的做法:

count = 0
for item in iterable:
 do_something(item)
 count += 1
 if count >= n: break

对我来说似乎并不整洁。另一种方法是:

for item in itertools.islice(iterable, n):
    do_something(item)

这看起来不错,问题是它与某些发电机一起使用的速度是否足够快?例如:

pair_generator = lambda iterable: itertools.izip(*[iter(iterable)]*2)
for item in itertools.islice(pair_generator(iterable), n):
 so_something(item)

与第一种方法相比,它的运行速度是否足够快? 有更简单的方法吗?

5 个答案:

答案 0 :(得分:15)

for item in itertools.islice(iterable, n):是最明显,最简单的方法。它适用于任意迭代,并且是O(n),就像任何理智的解决方案一样。

可以想象另一种解决方案可以有更好的表现;没有时间我们就不会知道。除非你profile你的代码并且发现这个电话是一个热点,否则我不建议打扰时机。除非它在内环中被掩埋,否则它将是非常值得怀疑的。过早优化是万恶之源。


如果我 要寻找替代解决方案,我会查看for count, item in enumerate(iterable): if count > n: break ...for i in xrange(n): item = next(iterator) ...之类的解决方案。我不认为这会有所帮助,但如果我们真的想比较一下,它们似乎值得尝试。如果我遇到我描述的情况并发现这是内循环中的热点(这真的是你的情况吗?),我还会尝试简化名称查找以获取{{ 1}}全局islice的属性,用于将函数绑定到本地名称。

这些是你在证明他们会帮助之后才做的事情。人们会尝试其他时间做很多事情。它并没有帮助使他们的程序明显更快;它只是让他们的节目变得更糟。

答案 1 :(得分:6)

itertools在直接适用时往往是最快的解决方案。

显然,检查的唯一方法是进行基准测试 - 例如,保存在aaa.py

import itertools

def doit1(iterable, n, do_something=lambda x: None):
  count = 0
  for item in iterable:
   do_something(item)
   count += 1
   if count >= n: break

def doit2(iterable, n, do_something=lambda x: None):
  for item in itertools.islice(iterable, n):
      do_something(item)

pair_generator = lambda iterable: itertools.izip(*[iter(iterable)]*2)

def dd1(itrbl=range(44)): doit1(itrbl, 23)
def dd2(itrbl=range(44)): doit2(itrbl, 23)

并看到......:

$ python -mtimeit -s'import aaa' 'aaa.dd1()'
100000 loops, best of 3: 8.82 usec per loop
$ python -mtimeit -s'import aaa' 'aaa.dd2()'
100000 loops, best of 3: 6.33 usec per loop

如此清楚,itertools在这里更快 - 使用您自己的数据进行基准测试以验证。

顺便说一句,我发现timeit在命令行中可以使用的更多,所以我总是使用它 - 它然后为你特定的速度运行正确的“数量级”循环试图测量,是那些10,100,1000等等 - 在这里,为了区分微秒和一半的差异,十万个循环是正确的。

答案 2 :(得分:2)

如果它是一个列表,那么你可以使用切片:

list[:n]

答案 3 :(得分:2)

您可以使用enumerate编写基本相同的循环,但使用更简单的Pythonic方式:

for idx, val in enumerate(iterableobj):
    if idx > n:
        break
    do_something(val)

答案 4 :(得分:1)

列表中的哪一项?试试

for k in mylist[0:n]:
     # do stuff with k

如果需要,你也可以使用理解

my_new_list = [blah(k) for k in mylist[0:n]]