2012-08-22 13 views
9

Desidero un funzionale enumerate-like su iteratori che produce la coppia (previous_element, current_element). Cioè, dato che iter èLa maggior parte del modo pythonic per ottenere l'elemento precedente

i0, i1, i1, ... 

Vorrei offset(iter) cedere

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

Non c'è un modo "più poderoso". Vedrete modi "più pitoni" (ad esempio, usando una funzione piuttosto che una classe con due classi di fabbrica per creare la prima classe), ma "pythonic" è un'idea soggettiva. –

+6

Fare clic su ✓ sotto una delle risposte per accettarlo. – lockstock

risposta

0

La migliore risposta che ho (e questo richiede itertools) è

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

ma mi sarebbe interessato a vedere se qualcuno ha un one-liner (o un nome migliore di offset per questa funzione)!

+1

Questo non funziona correttamente sugli iteratori (al contrario di iterabili). Ad esempio: 'lista (offset (i per i in xrange (10))) restituisce ' [(Nessuno, 0), (1, 2), (3, 4), (5, 6), (7, 8)] '. – Dougal

+0

L'idea generale è buona qui, devi solo creare 2 iteratori indipendenti sull'iteratore dato usando 'tee'. Vedi la mia risposta. – 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) 

EDIT spostato doc string nella funzione

+0

Non ti dà '(None, i0)' per la prima coppia – MattH

+1

@MattH Facile da risolvere; cambiate la riga 'b.next()' a 'yield (None, b.next())' (e quindi passate il ciclo sopra 'izip' e producete, o usate la sintassi 'yield from' di Python 3.3. – Dougal

+0

@MattH, sì, lo so. Suppongo che l'OP sarà in grado di elaborare i dettagli. Questo codice proviene dai documenti ed è considerato un suggerimento per il problema. – bpgergo

26

cosa circa la soluzione più semplice (ovvio)?

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

Mi sembra buono, penso di avere qualcosa di molto simile in un repository molto vicino. – MattH

+0

Sì, questo era solo * troppo * ovvio ... – sloth

+0

Non so perché tutti saltano su "itertools" per questo. Perché usare una mazza e un picco ferroviario quando una puntina da disegno andrà bene? – mgilson

8

di mettere più itertools sul tavolo:

from itertools import tee, izip, chain 

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

+1 Mi piace. – 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 = questo. Il meglio di due mondi :).

Problemi correlati