2012-08-22 16 views
9

Chciałbym funkcji podobnej do enumerate na iteratory, które dają parę (previous_element, current_element). Oznacza to, że biorąc pod uwagę, że iter jestNajbardziej pythonic sposób na uzyskanie poprzedniego elementu

i0, i1, i1, ... 

Chciałbym offset(iter) uzyskując

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

Nie ma "najbardziej pythonic" sposób. Zobaczysz "bardziej pythonic" sposoby (np. Używając funkcji zamiast klasy z dwiema klasami fabrycznymi do stworzenia pierwszej klasy), ale "pythonic" jest subiektywną ideą. –

+6

Kliknij ✓ poniżej jednej z odpowiedzi, aby ją zaakceptować. – lockstock

Odpowiedz

0

najlepszą odpowiedź mam (i to wymaga itertools) jest

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

ale byłbym zainteresowani widzeniem, czy ktoś ma jedno-liniowy (lub lepsze imię niż offset dla tej funkcji)!

+1

To nie działa poprawnie w iteratorach (w przeciwieństwie do iterables). Na przykład: 'list (offset (i dla i w xrange (10)))' zwraca '[(None, 0), (1, 2), (3, 4), (5, 6), (7, 8)] '. – Dougal

+0

Ogólna idea jest tutaj dobra, wystarczy wykonać 2 niezależne iteratory nad danym iteratorem za pomocą 'tee'. Zobacz moją odpowiedź. – 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 przeniósł doc ciąg do funkcji

+0

Nie daje '(None, i0)' dla pierwszej pary – MattH

+1

@MattH Easy to fix; zmień linię 'b.next()' na 'yield (None, b.next())' (a następnie przeprowadź pętlę nad 'izip' i wydajnością lub użyj Pythona 3.3' yield from' syntax). – Dougal

+0

@MattH, tak, wiem. Przypuszczam, że PO będzie w stanie opracować szczegóły. Ten kod pochodzi z dokumentacji i jest uważany za wskazówkę dotyczącą problemu. – bpgergo

26

Co o proste rozwiązanie (oczywiste)?

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

Wygląda dobrze, myślę, że mam coś bardzo podobnego w bardzo repozytorium w pobliżu. – MattH

+0

Tak, ten był po prostu * zbyt * oczywisty ... – sloth

+0

Nie wiem, dlaczego wszyscy przeskakują po tym 'itertools'. Po co używać młota i kolca, kiedy pinezka zrobi? – mgilson

8

Aby umieścić więcej itertools na stole:

from itertools import tee, izip, chain 

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

+1 Podoba mi się to. – 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 = to. Najlepsze z dwóch światów :).

Powiązane problemy