2010-01-26 2 views
63

Каков наилучший способ получить последний элемент из итератора в Python 2.6? Например, скажем,Самый чистый способ получить последний элемент из итератора Python

my_iter = iter(range(5)) 

Что кратчайшее код/​​чистый способ получения 4 от my_iter?

Я мог бы это сделать, но это не кажется очень эффективным:

[x for x in my_iter][-1] 
+4

итераторы Предположим, что вы хотите, чтобы перебирать элементы и не имеют доступа к последним элементам. Что мешает вам просто использовать диапазон (5) [- 1]? – Frank

+5

@Frank - Я предположил, что фактический итератор был более сложным и/или более удаленным и/или сложнее управлять, чем 'iter (range (5))' –

+3

@Frank: факт, что на самом деле это гораздо более сложная функция генератора, которая обеспечивает итератор. Я просто сделал этот пример так, чтобы было просто и понятно, что происходит. – Peter

ответ

58
item = defaultvalue 
for item in my_iter: 
    pass 
+2

Почему placeholder «defaultvalue»? Почему бы не «Нет»? Это именно то, для чего «Нет». Вы предполагаете, что некоторые значения по умолчанию для конкретной функции могут быть даже правильными? Если итератор фактически не выполняет итерацию, то внеполосное значение * больше * значимо, чем некоторая вводящая в заблуждение функция по умолчанию. –

+29

Значение по умолчанию - это просто заполнитель для моего примера. Если вы хотите использовать значение «Нет» в качестве значения по умолчанию, это ваш выбор. Никто не всегда является самым разумным дефолтом и даже не может быть вне диапазона. Лично я склонен использовать 'defaultvalue = object()', чтобы убедиться, что это действительно уникальное значение. Я просто указываю, что выбор значения по умолчанию выходит за рамки этого примера. –

+24

@ S.Lott: возможно, полезно различать разницу между пустым итератором и итератором, который имеет «Нет», поскольку он является окончательным значением –

2

Я хотел бы использовать reversed, за исключением того, что она принимает только последовательности вместо итераторов, который кажется довольно произвольным.

Как вы это сделаете, вам придется пробежать весь итератор. При максимальной эффективности, если вам не нужен итератор еще раз, вы могли бы просто мусор все значения:

for last in my_iter: 
    pass 
# last is now the last item 

Я думаю, что это суб-оптимальное решение, хотя.

+2

reverseed() не принимает итератор, просто последовательности. –

+2

Это совсем не произвольно. Единственный способ перевернуть итератор - это итерация до конца, сохраняя все элементы в памяти. I, e, вам нужно сначала сделать последовательность из нее, прежде чем вы сможете ее отменить. Что, конечно же, в первую очередь поражает цель итератора, а также означает, что вы внезапно воспользуетесь большой памятью без видимых причин. Так что на самом деле это противоположность произвольным. :) –

+0

@ Lennart - Когда я сказал произвольный, я имел в виду раздражение. Я сосредоточил свои языковые навыки на своей бумаге в течение нескольких часов в это время утром. –

3

Там в этот

list(the_iter)[-1] 

Если длина итерации действительно эпическая - так долго, что материализации список исчерпает память - то вам действительно нужно пересмотреть дизайн.

+0

Это самое простое решение. – laike9m

+2

Мягко лучше использовать кортеж. –

+4

Категорически не согласен с последним предложением. Работа с очень большими наборами данных (которые могут превышать границы памяти, если они загружаются сразу), является основной причиной использования итератора вместо списка. – Paul

18

Это вряд ли будет быстрее, чем пустой цикл в связи с лямбда, но, возможно, это даст кому-то еще на мысль

reduce(lambda x,y:y,my_iter) 

Если ИТЭР пуст, то TypeError поднимается

27

Возможно, стоит использовать __reversed__, если он доступен

if hasattr(my_iter,'__reversed__'): 
    last = next(reversed(my_iter)) 
else: 
    for last in my_iter: 
     pass 
-7

вопрос неправильно и может привести только к ответу, который является сложным и неэффективным. Чтобы получить итератор, вы, конечно же, начинаете с чего-то итеративного, что в большинстве случаев будет предлагать более прямой способ доступа к последнему элементу.

Как только вы создадите итератор из итерабельного, вы застреваете в элементах, потому что это единственное, что обеспечивает итерация.

Таким образом, самый эффективный и понятный способ - не создавать итератор в первую очередь, а использовать собственные методы доступа к итерабельному.

+2

Итак, как бы вы получили последнюю строку файла? –

+0

@ BriceM.Dempsey: пропустите до конца, найдите '\ n' назад –

38

Используйте deque размера 1.

from collections import deque 

#aa is an interator 
aa = iter('apple') 

dd = deque(aa, maxlen=1) 
last_element = dd.pop() 
+3

Это самый быстрый способ исчерпать длинную последовательность, хотя и только слабее быстрее, чем цикл for. –

+7

+1 для того, чтобы быть технически корректным, но у читателей должны быть обычные предостережения Python: «Вам действительно нужно оптимизировать это?», «Это менее явное, а не Pythonic», и «Более быстрая скорость зависит от реализации, которые могут измениться ». – leewz

+1

также, это память-hog –

1

Смотрите этот код что-то подобное:

http://excamera.com/sphinx/article-islast.html

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

[(last, e) for (last, e) in islast(the_iter) if last] 
+1

Пожалуйста, введите код для 'islast' в свой ответ (см. Http://meta.stackexchange.com/questions/8231/are-answers-that-just-contain-links-elsewhere-really-good-answers). –

15

Как просто:

max(enumerate(the_iter))[1] 
+4

О, это умно. Не самый эффективный или читаемый, но умный. – timgeb

+0

Итак, просто думайте вслух ... Это работает, потому что 'enumerate' возвращает' (index, value) 'like:' (0, val0), (1, val1), (2, val2) '... а затем default 'max', если задан список кортежей, сравнивается только с первым значением кортежа, если только два первых значения не равны, а они никогда не присутствуют здесь, потому что они представляют индексы. Тогда конечный индекс - это то, что max возвращает полный (idx, value) кортеж, тогда как нас интересует только 'value'. Интересная идея. –

0

я бы просто использовать next(reversed(myiter))

+2

ТипError: аргумент reverse() должен быть последовательностью – Labo

9

Если вы используете питона 3.x:

*_, last = iterator 
print(last) 

если вы используете Python 2.7:

last = next(iterator) 
for last in iterator: 
    continue 
print last 
Смежные вопросы