2012-08-22 13 views
9

Me gustaría un enumerate -like funcional en los iteradores que produce el par (previous_element, current_element). Es decir, dado que iter esLa manera más pitónica de obtener el elemento anterior

i0, i1, i1, ... 

me gustaría offset(iter) para producir

(None, i0), (i0, i1), (i1, i2) ... 
+2

No hay una manera "más pythonic". Vas a ver formas "más pythonic" (por ejemplo, usar una función en lugar de una clase con dos clases de fábrica para crear la primera clase), pero "pythonic" es una idea subjetiva. –

+6

Haga clic en ✓ debajo de una de las respuestas para aceptarlo. – lockstock

Respuesta

0

La mejor respuesta que tengo (y esto requiere itertools) es

def offset(iter, n=1): 
    # returns tuples (None, iter0), (iter0, iter1), (iter1, iter2) ... 
    previous = chain([None] * n, iter) 
    return izip(previous, iter) 

pero habría ¡interesado en ver si alguien tiene un trazador de líneas (o un nombre mejor que el equivalente para esta función)!

+1

Esto no funciona correctamente en los iteradores (a diferencia de los iterables). Por ejemplo: 'list (offset (i para i en xrange (10)))' devuelve '[(None, 0), (1, 2), (3, 4), (5, 6), (7, 8)] '. – Dougal

+0

La idea general es buena aquí, solo necesitas hacer 2 iteradores independientes sobre el iterador dado usando 'tee'. Ver mi respuesta – Kos

2
def pairwise(iterable): 
    """s -> (s0,s1), (s1,s2), (s2, s3), ... 
    see http://docs.python.org/library/itertools.html 
    """ 
    a, b = itertools.tee(iterable) 
    b.next() 
    return itertools.izip(a, b) 

EDITAR trasladó cadena de documentación en la función

+0

No le da '(Ninguno, i0)' para el primer par – MattH

+1

@MattH Fácil de arreglar; cambie la línea 'b.next()' a 'yield (None, b.next())' (y luego repita sobre 'izip' y yield, o use la sintaxis 'yield from' de Python 3.3). – Dougal

+0

@MattH, sí, lo sé. Supongo que OP podrá resolver los detalles. Este código es de los documentos y se considera una pista para el problema en la mano. – bpgergo

26

¿Qué pasa con la simple solución (obvio)?

def offset(iterable): 
    prev = None 
    for elem in iterable: 
     yield prev, elem 
     prev = elem 
+0

Me parece bien, creo que tengo algo muy similar en un repositorio muy cerca. – MattH

+0

Sí, este fue solo * demasiado * obvio ... – sloth

+0

No sé por qué todo el mundo está saltando sobre 'itertools' para esto. ¿Por qué usar un mazo y un pico de ferrocarril cuando un chinche va a hacer? – mgilson

8

poner más itertools sobre la mesa:

from itertools import tee, izip, chain 

def tee_zip(iterable): 
    a, b = tee(iterable) 
    return izip(chain([None], a), b) 
+0

+1 Me gusta esto. – jamylak

1
def offset(iter, n=1, pad=None): 
    i1, i2 = itertools.tee(iter) 
    i1_padded = itertools.chain(itertools.repeat(pad, n), i1) 
    return itertools.izip(i1_padded, i2) 

@bpgergo + @ = user792036 esto. Lo mejor de dos mundos :).

Cuestiones relacionadas