2013-11-20 2 views
1

Я пытаюсь выполнить проверки первого и последнего элементов интернатора. Он имеет несколько тысяч записей, поэтому мне нужен оперативный метод проверки. Если найдено this post, это поставило меня на эту стратегию.Самый быстрый способ получить первый и последний элемент итератора python

first = True 
for value in iterator: 
    if first: 
     do_stuff_to_first_iter 
     first = False 
    else: 
     pass 
do_stuff_to_last_iter 

У кого-нибудь есть мнение по более быстрому способу выполнения этого? Большое спасибо!

+2

Почему должен ли произвольный итератор иметь последний элемент? – Hyperboreus

+1

Ваш пример кода недействителен python; вы могли бы хотя бы использовать 'для элемента в итерабельном:' или аналогичный синтаксис Python? –

+0

Обратите внимание, что 'else: pass' является * полностью * избыточным и может быть полностью удалено. В Python у вас нет * have * для предложения 'else' с оператором' if'. –

ответ

13

Получить первое значение с next() function:

first = last = next(iterable, defaultvalue) 
for last in iterable: 
    pass 

Это предполагает, что итерация конечна.

Для пустых итерируемых, first и last установлены на defaultvalue. Для итерации только одним элементом, first и last будут ссылаться на этот один элемент. Для любого другого конечного итерабельного, first будет иметь первый элемент, last самый последний.

+0

Привет, Martijn, спасибо за ответ. Этот метод очень pythonic и (теперь, когда я разработал все ошибки), кажется, работает очень хорошо. По-прежнему требуется около 4 минут, чтобы пройти через мой итератор, но это лучше, чем у меня раньше. Еще раз спасибо. – Rich

+0

ОК, поэтому я приурочил это к методу «deque» Павла. Этот метод взял мой процесс за 264 секунды. Метод 'deque' занял 275 секунд. В пределах шума, так сказать. Но я собираюсь использовать этого парня! Благодарю. – Rich

3

Основываясь на моем ответе на вопрос: связан

Возможно, стоит использовать __reversed__, если он доступен. Если вы предоставляете итератор, и есть разумный способ реализации __reversed__ (т.е. без перебора от конца до конца), вы должны сделать это

first = last = next(my_iter) 
if hasattr(my_iter,'__reversed__'): 
    last = next(reversed(my_iter)) 
else: 
    for last in my_iter: 
     pass 
+1

'__reversed__' обычно встречается только на объектах, которые сами не являются итераторами. Например. 'list' предоставляет его, но не' iter (list) '. –

+1

В стандартной библиотеке только 'list()', 'range()', 'collections.deque()' и 'collections.OrderedDict()' предоставляют '__reversed__', и ни один из них не является итераторами. Это означает, что вы ** не можете ** называть 'next()' на них. –

+0

Мне нравится возможность изменения итератора и избежания ненужных циклов. К сожалению, у моего итератора нет атрибута '__reversed__', и я все равно остаюсь в цикле. Спасибо за предложение! – Rich

1

Вы можете использовать Deque с MAXLEN 1, чтобы быстро получить последний элемент конечного итератора:

>>> from collections import deque 
>>> last_getter = deque(maxlen=1) 
>>> seq = range(10000) 
>>> iseq = iter(seq) 
>>> 
>>> first = last = next(iseq, None) 
>>> last_getter.extend(iseq) 
>>> if last_getter: last = last_getter[0] 
... 
>>> print (first, last) 
0 9999 
+1

Итак, я попробовал этот метод и приурочил его к моему процессу. Взял 275 секунд. Техника «loop n 'pass» заняла 264 секунды. В любом случае, оба они сопоставимы. Спасибо за предложение! Это интересная техника, о которой я не знал. – Rich

1

по моим тестам, islice это в 3 раза быстрее, чем for: pass или deque. Это потребует, чтобы вы знали, сколько предметов там будет.

last = next(islice(iterable, length - 1, length)) 

Или, если вы не знаете, на всю длину, но не знаю, что это должно быть, по крайней мере n, еще можно было «пропустить», чтобы n в качестве ярлыка:

rest = islice(iterable, n, None) 
last = next(rest) 
for last in rest: 
    pass 
Смежные вопросы