Maneira mais limpa de obter o último item do iterador Python
-
22-09-2019 - |
Pergunta
Qual é a melhor maneira de obter o último item de um iterador em Python 2.6?Por exemplo, digamos
my_iter = iter(range(5))
Qual é o código mais curto/maneira mais limpa de obter 4
de my_iter
?
Eu poderia fazer isso, mas não parece muito eficiente:
[x for x in my_iter][-1]
Solução
item = defaultvalue
for item in my_iter:
pass
Outras dicas
Use um deque
do tamanho 1.
from collections import deque
#aa is an interator
aa = iter('apple')
dd = deque(aa, maxlen=1)
last_element = dd.pop()
Se você estiver usando o Python 3.x:
*_, last = iterator # for a better understanding check PEP 448
print(last)
Se você estiver usando o Python 2.7:
last = next(iterator)
for last in iterator:
continue
print last
NB:
Geralmente a solução apresentada acima é o que você precisa para casos regulares, mas se você estiver lidando com grande quantidade de dados, é mais eficiente usar um deque
do tamanho 1. (fonte)
from collections import deque
#aa is an interator
aa = iter('apple')
dd = deque(aa, maxlen=1)
last_element = dd.pop()
Provavelmente vale a pena usar __reversed__
Se estiver disponível
if hasattr(my_iter,'__reversed__'):
last = next(reversed(my_iter))
else:
for last in my_iter:
pass
Tão simples quanto:
max(enumerate(the_iter))[1]
É improvável que isso seja mais rápido que o vazio por loop devido ao lambda, mas talvez isso dê uma ideia a alguém
reduce(lambda x,y:y,my_iter)
Se o iter estiver vazio, um TypeError será elevado
Lá está isso
list( the_iter )[-1]
Se a duração da iteração for verdadeiramente épica - tanto quanto materializar a lista esgotará a memória - você realmente precisa repensar o design.
eu usaria reversed
, exceto que são necessárias apenas sequências em vez de iteradores, o que parece bastante arbitrário.
De qualquer maneira, você terá que correr por todo o iterador. Com a máxima eficiência, se você nunca mais precisar do iterador, poderá simplesmente destruir todos os valores:
for last in my_iter:
pass
# last is now the last item
Eu acho que esta é uma solução subótima, no entanto.
o Toolz A biblioteca fornece uma boa solução:
from toolz.itertoolz import last
last(values)
Mas adicionar uma dependência não essencial pode não valer a pena por usá-la apenas neste caso.
Veja este código para algo semelhante:
http://excamera.com/sphinx/article-islast.html
Você pode usá -lo para pegar o último item com:
[(last, e) for (last, e) in islast(the_iter) if last]
Eu apenas usaria next(reversed(myiter))
A questão é obter o último elemento de um iterador, mas se o seu iterador for criado aplicando condições a uma sequência, então revertido pode ser usado para encontrar o "primeiro" de uma sequência revertida, apenas olhando para os elementos necessários, aplicando reverter para a própria sequência.
Um exemplo artificial,
>>> seq = list(range(10))
>>> last_even = next(_ for _ in reversed(seq) if _ % 2 == 0)
>>> last_even
8
Alternativamente para iteradores infinitos que você pode usar:
from itertools import islice
last = list(islice(iterator(), 1000))[-1] # where 1000 is number of samples
Eu pensei que seria mais lento então deque
Mas é tão rápido e na verdade é mais rápido do que o método de loop (de alguma forma)
A pergunta está errada e só pode levar a uma resposta complicada e ineficiente. Para obter um iterador, é claro que você começa a partir de algo que é iterável, que, na maioria dos casos, oferecerá uma maneira mais direta de acessar o último elemento.
Depois de criar um iterador a partir de um iterável, você está preso ao passar pelos elementos, porque essa é a única coisa que um iterável fornece.
Portanto, a maneira mais eficiente e clara não é criar o iterador em primeiro lugar, mas usar os métodos de acesso nativo do iterável.