As soluções até agora lidam apenas com listas, e a maioria está copiando a lista. Na minha experiência, muitas vezes isso não é possível.
Além disso, eles não lidam com o fato de que você pode ter elementos repetidos na lista.
O título da sua pergunta diz " Valores anteriores e próximos dentro de um loop ", mas se você executar a maioria das respostas aqui dentro de um loop, acabará iterando a lista inteira novamente em cada elemento para encontrá-lo.
Acabei de criar uma função que. usando o itertools
módulo, divide e divide o iterável e gera tuplas com os elementos anteriores e seguintes juntos. Não é exatamente o que seu código faz, mas vale a pena dar uma olhada, porque provavelmente pode resolver seu problema.
from itertools import tee, islice, chain, izip
def previous_and_next(some_iterable):
prevs, items, nexts = tee(some_iterable, 3)
prevs = chain([None], prevs)
nexts = chain(islice(nexts, 1, None), [None])
return izip(prevs, items, nexts)
Em seguida, use-o em um loop e você terá os itens anteriores e os próximos nele:
mylist = ['banana', 'orange', 'apple', 'kiwi', 'tomato']
for previous, item, nxt in previous_and_next(mylist):
print "Item is now", item, "next is", nxt, "previous is", previous
Os resultados:
Item is now banana next is orange previous is None
Item is now orange next is apple previous is banana
Item is now apple next is kiwi previous is orange
Item is now kiwi next is tomato previous is apple
Item is now tomato next is None previous is kiwi
Funcionará com qualquer lista de tamanho (porque não copia a lista), e com qualquer iterável (arquivos, conjuntos, etc). Dessa forma, você pode apenas iterar sobre a sequência e ter os itens anteriores e posteriores disponíveis dentro do loop. Não há necessidade de pesquisar novamente o item na sequência.
Uma breve explicação do código:
tee
é usado para criar com eficiência 3 iteradores independentes sobre a sequência de entrada
chain
liga duas sequências em uma; é usado aqui para anexar uma sequência de elemento único [None]
aprevs
islice
é usado para fazer uma sequência de todos os elementos exceto o primeiro, então chain
é usado para adicionar a None
ao seu final
- Existem agora 3 sequências independentes baseadas em
some_iterable
que se parecem com:
prevs
: None, A, B, C, D, E
items
: A, B, C, D, E
nexts
: B, C, D, E, None
- finalmente
izip
é usado para alterar 3 sequências em uma sequência de tripletos.
Observe que izip
para quando qualquer sequência de entrada se esgota, então o último elemento de prevs
será ignorado, o que é correto - não existe tal elemento que o último elemento seria seu prev
. Poderíamos tentar remover os últimos elementos, prevs
mas izip
o comportamento torna isso redundante
Observe também que tee
, izip
, islice
e chain
vêm do itertools
módulo; eles operam em suas sequências de entrada em tempo real (preguiçosamente), o que os torna eficientes e não introduz a necessidade de ter toda a sequência na memória de uma vez a qualquer momento.
Em python 3
, ele mostrará um erro durante a importação izip
, você pode usar em zip
vez de izip
. Não há necessidade de importação zip
, que é pré-definido na python 3
- fonte