Python: valores anteriores y siguientes dentro de un bucle

¿Cómo puedo hacer algo así en python?

foo = somevalue previous = next = 0 for (i=1; i<objects.length(); i++) { if (objects[i]==foo){ previous = objects[i-1] next = objects[i+1] } } 

Related of "Python: valores anteriores y siguientes dentro de un bucle"

Esto debería funcionar.

 foo = somevalue previous = next_ = None l = len(objects) for index, obj in enumerate(objects): if obj == foo: if index > 0: previous = objects[index - 1] if index < (l - 1): next_ = objects[index + 1] 

Aquí están los documentos en la función de enumerate .

Las soluciones hasta ahora solo tratan con listas, y la mayoría está copiando la lista. En mi experiencia muchas veces eso no es posible.

Además, no tratan el hecho de que puede tener elementos repetidos en la lista.

El título de su pregunta dice ” Valores anteriores y siguientes dentro de un bucle “, pero si ejecuta la mayoría de las respuestas aquí dentro de un bucle, terminará iterando sobre la lista completa en cada elemento para encontrarlo.

Así que acabo de crear una función que. Usando el módulo itertools , divide y rebana el iterable, y genera tuplas con los elementos anterior y siguiente juntos. No es exactamente lo que hace su código, pero vale la pena echarle un vistazo, ya que probablemente pueda resolver su 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) 

Luego, utilícelo en un bucle, y tendrá elementos anteriores y siguientes en él:

 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 

Los 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á con cualquier lista de tamaño (porque no copia la lista) y con cualquier iterable (archivos, conjuntos, etc.). De esta manera, solo puede iterar sobre la secuencia y tener los elementos anterior y siguiente disponibles dentro del bucle. No es necesario buscar nuevamente el elemento en la secuencia.

Una breve explicación del código:

  • tee se utiliza para crear eficientemente 3 iteradores independientes sobre la secuencia de entrada
  • chain une dos secuencias en una; se usa aquí para agregar una secuencia de un solo elemento [None] a prevs
  • islice se usa para hacer una secuencia de todos los elementos excepto el primero, luego la chain se usa para agregar un None a su final
  • Ahora hay 3 secuencias independientes basadas en some_iterable que parecen:
    • prevs : None, A, B, C, D, E
    • items : A, B, C, D, E
    • nexts : B, C, D, E, None
  • Finalmente, se utiliza izip para cambiar 3 secuencias en una secuencia de tripletes.

Tenga en cuenta que izip detiene cuando se agota cualquier secuencia de entrada, por lo que se ignorará el último elemento de prevs , lo cual es correcto: no hay tal elemento que el último elemento sea su prev . Podríamos intentar quitar los últimos elementos de prevs pero el comportamiento de prevs hace que sea redundante.

También tenga en cuenta que tee , islice , islice y chain provienen del módulo itertools ; operan en sus secuencias de entrada sobre la marcha (perezosamente), lo que las hace eficientes y no introduce la necesidad de tener toda la secuencia en la memoria de una vez y en cualquier momento.

En python 3 , mostrará un error al importar izip , puedes usar zip lugar de izip . No es necesario importar zip , está predefinido en python 3 – source

Usando una lista de comprensión, devuelva una tupla de 3 con los elementos actuales, anteriores y siguientes:

 three_tuple = [(current, my_list[idx - 1] if idx >= 1 else None, my_list[idx + 1] if idx < len(my_list) - 1 else None) for idx, current in enumerate(my_list)] 

Aquí hay una versión que usa generadores sin errores de límite:

 def trios(input): input = iter(input) # make sure input is an iterator try: prev, current = input.next(), input.next() except StopIteration: return for next in input: yield prev, current, next prev, current = current, next def find_prev_next(objects, foo): prev, next = 0, 0 for temp_prev, current, temp_next in trios(objects): if current == foo: prev, next = temp_prev, temp_next return prev, next print find_prev_next(range(10), 1) print find_prev_next(range(10), 0) print find_prev_next(range(10), 10) print find_prev_next(range(0), 10) print find_prev_next(range(1), 10) print find_prev_next(range(2), 10) 

Tenga en cuenta que el comportamiento de los límites es que nunca buscamos “foo” en el primer o último elemento, a diferencia de su código. Una vez más, la semántica de los límites es extraña … y es difícil de entender a partir de su código 🙂

uso de expresiones condicionales para la concisión de python> = 2.5

 def prenext(l,v) : i=l.index(v) return l[i-1] if i>0 else None,l[i+1] if i>> (2,4) prenext(x,0) >>> (None,2) prenext(x,9) >>> (8,None) 

Puede usar el index en la lista para encontrar dónde está somevalue y luego obtener el anterior y el siguiente según sea necesario:

def find_prev_next(elem, elements): previous, next = None, None index = elements.index(elem) if index > 0: previous = elements[index -1] if index < (len(elements)-1): next = elements[index +1] return previous, next foo = 'three' list = ['one','two','three', 'four', 'five'] previous, next = find_prev_next(foo, list) print previous # should print 'two' print next # should print 'four'
def find_prev_next(elem, elements): previous, next = None, None index = elements.index(elem) if index > 0: previous = elements[index -1] if index < (len(elements)-1): next = elements[index +1] return previous, next foo = 'three' list = ['one','two','three', 'four', 'five'] previous, next = find_prev_next(foo, list) print previous # should print 'two' print next # should print 'four' 

AFAIK esto debería ser bastante rápido, pero no lo probé:

 def iterate_prv_nxt(my_list): prv, cur, nxt = None, iter(my_list), iter(my_list) next(nxt, None) while True: try: if prv: yield next(prv), next(cur), next(nxt, None) else: yield None, next(cur), next(nxt, None) prv = iter(my_list) except StopIteration: break 

Ejemplo de uso:

 >>> my_list = ['a', 'b', 'c'] >>> for prv, cur, nxt in iterate_prv_nxt(my_list): ... print prv, cur, nxt ... None ab abc bc None 

Usando generadores, es bastante simple:

 signal = ['→Signal value←'] def pniter( iter, signal=signal ): iA = iB = signal for iC in iter: if iB is signal: iB = iC continue else: yield iA, iB, iC iA = iB iB = iC iC = signal yield iA, iB, iC if __name__ == '__main__': print('test 1:') for a, b, c in pniter( range( 10 )): print( a, b, c ) print('\ntest 2:') for a, b, c in pniter([ 20, 30, 40, 50, 60, 70, 80 ]): print( a, b, c ) print('\ntest 3:') cam = { 1: 30, 2: 40, 10: 9, -5: 36 } for a, b, c in pniter( cam ): print( a, b, c ) for a, b, c in pniter( cam ): print( a, a if a is signal else cam[ a ], b, b if b is signal else cam[ b ], c, c if c is signal else cam[ c ]) print('\ntest 4:') for a, b, c in pniter([ 20, 30, None, 50, 60, 70, 80 ]): print( a, b, c ) print('\ntest 5:') for a, b, c in pniter([ 20, 30, None, 50, 60, 70, 80 ], ['sig']): print( a, b, c ) print('\ntest 6:') for a, b, c in pniter([ 20, ['→Signal value←'], None, '→Signal value←', 60, 70, 80 ], signal ): print( a, b, c ) 

Tenga en cuenta que las pruebas que incluyen Ninguno y el mismo valor que el valor de la señal siguen funcionando, porque la comprobación del valor de la señal utiliza “es” y la señal es un valor que Python no realiza internamente. Sin embargo, cualquier valor de marcador de singleton se puede utilizar como una señal, lo que podría simplificar el código de usuario en algunas circunstancias.

Manera pythonica y elegante:

 objects = [1, 2, 3, 4, 5] value = 3 if value in objects: index = objects.index(value) previous_value = objects[index-1] next_value = objects[index+1] if index + 1 < len(objects) else None