Быстро выполняя итерации по первым n объектам повторяемого (не список) в 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)

Это будет работать достаточно быстро по сравнению с первым методом? Там некоторый более легкий путь состоит в том, чтобы сделать это?

12
задан martinthenext 23 April 2010 в 22:01
поделиться

5 ответов

для элемента в itertools.islice (iterable, n): - наиболее очевидный и простой способ сделать это. Он работает для произвольных итераций и O (n), как и любое разумное решение.

Вполне возможно, что другое решение могло бы иметь лучшую производительность; мы бы не узнали без времени. Я бы не рекомендовал беспокоиться о времени, если вы не профилируете свой код и не обнаружите, что этот вызов является точкой доступа. Если он не закопан во внутренний цикл, очень сомнительно, что так оно и будет. Преждевременная оптимизация - корень всех зол.


Если бы я собирался искать альтернативные решения, я бы посмотрел на такие, как для count, item in enumerate (итерация): if count> n: break ... и для i в xrange (n): item = next (итератор) ... . Я бы не подумал, что это поможет, но, похоже, их стоит попробовать, если мы действительно хотим сравнить вещи.Если бы я застрял в ситуации, когда я профилировал и обнаружил, что это горячая точка во внутреннем цикле (действительно ли это ваша ситуация?), Я бы также попытался упростить поиск имени от получения islice глобального iterools для привязки функции к локальному имени уже.

Это то, что вы делаете только после того, как докажете, что они помогают. В другой раз люди стараются делать то же самое. Это не помогает сделать их программы заметно быстрее; это только ухудшает их программы.

15
ответ дан 2 December 2019 в 05:53
поделиться

Если это список, вы можете использовать нарезку:

list[:n]
2
ответ дан 2 December 2019 в 05:53
поделиться

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 и так далее - здесь, чтобы различить разницу в полторы микросекунды, сто тысяч петель - это примерно правильно.

6
ответ дан 2 December 2019 в 05:53
поделиться

Вы можете использовать enumerate , чтобы написать практически тот же цикл, что и у вас, но более простым, питоническим способом:

for idx, val in enumerate(iterableobj):
    if idx > n:
        break
    do_something(val)
2
ответ дан 2 December 2019 в 05:53
поделиться

Из списка? Попробуйте

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

, вы также можете использовать понимание, если вам нужно

my_new_list = [blah(k) for k in mylist[0:n]]
1
ответ дан 2 December 2019 в 05:53
поделиться
Другие вопросы по тегам:

Похожие вопросы: