簡體   English   中英

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

[英]Fast iterating over first n items of an iterable (not a list) in python

我正在尋找一種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)

與第一種方法相比,它運行得足夠快嗎? 有沒有更簡單的方法呢?

for item in itertools.islice(iterable, n):是最明顯,最簡單的方法。 它適用於任意迭代,並且是O(n),就像任何理智的解決方案一樣。

可以想象,另一種解決方案可以有更好的性能; 沒有時間我們就不會知道。 我不建議打擾時間,除非你描述你的代碼並發現這個電話是一個熱點。 除非它在內環中被掩埋,否則它將是非常值得懷疑的。 過早優化是萬惡之源。


如果要去尋找替代解決方案,我想看看那些象for count, item in enumerate(iterable): if count > n: break ...for i in xrange(n): item = next(iterator) ... 我不認為這會有所幫助,但如果我們真的想比較一下,它們似乎值得嘗試。 如果我被困在我描述的情況下,發現這是一個內循環中的熱點 (這真的是你的情況嗎?),我還會嘗試簡化名稱查找,使全局iteroolsislice屬性綁定到已經成為本地名稱的功能。

這些是你在證明他們會幫助之后才做的事情。 人們會嘗試其他時間做很多事情。 它並沒有幫助使他們的程序明顯更快; 它只會使他們的程序變得更糟。

當直接適用時, 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等等 - 在這里,為了區分微秒和一半的差異,十萬個循環是正確的。

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

list[:n]

您可以使用枚舉來編寫與您相同的循環,但使用更簡單的Pythonic方式:

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

一個清單? 嘗試

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

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

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM