Frage

Ich möchte ein Algorithmus zur Liste Scheiben iterieren. Scheiben Größe außerhalb der Funktion festgelegt und kann unterschiedlich sein.

In meinem Kopf ist es so etwas wie:

for list_of_x_items in fatherList:
    foo(list_of_x_items)

Gibt es eine Möglichkeit, um richtig list_of_x_items zu definieren oder eine andere Art und Weise, dies zu tun mit Python 2.5?


edit1: Klarstellung Both „Partitionieren“ und „Schiebefenster“ geltenden Bedingungen klingen zu meiner Aufgabe, aber ich bin kein Experte. So löse ich das Problem ein wenig tiefer erklären und auf die Frage hinzu:

Die fatherList ist ein Multi-Level-numpy.array ich aus einer Datei immer bin. Funktion hat Mittelwert der Serie finden (Benutzer stellen die Länge der Serie) Für durchschnittlich ich die mean() Funktion verwenden. Jetzt Frage Erweiterung:

edit2: So wird die Funktion ändern Sie zur Verfügung gestellt haben, um die zusätzlichen Elemente zu speichern und nutzen, wenn der nächste fatherList zur Funktion zugeführt wird,

?

zum Beispiel, wenn die Liste ist Länge 10 und die Größe eines Chunk 3 ist, dann wird das 10. Mitglied der Liste gespeichert und zu Beginn der nächsten Liste angehängt.


Related:

War es hilfreich?

Lösung

Antwort auf den letzten Teil der Frage:

  

Frage Update: Wie das ändern   Funktion, die Sie zum Speichern zur Verfügung gestellt haben   die zusätzlichen Elemente und verwenden Sie sie, wenn die   nächster fatherList ist die Fed   Funktion?

Wenn Sie speichern Zustand benötigen, dann können Sie ein Objekt für diese verwenden.

class Chunker(object):
    """Split `iterable` on evenly sized chunks.

    Leftovers are remembered and yielded at the next call.
    """
    def __init__(self, chunksize):
        assert chunksize > 0
        self.chunksize = chunksize        
        self.chunk = []

    def __call__(self, iterable):
        """Yield items from `iterable` `self.chunksize` at the time."""
        assert len(self.chunk) < self.chunksize
        for item in iterable:
            self.chunk.append(item)
            if len(self.chunk) == self.chunksize:
                # yield collected full chunk
                yield self.chunk
                self.chunk = [] 

Beispiel:

chunker = Chunker(3)
for s in "abcd", "efgh":
    for chunk in chunker(s):
        print ''.join(chunk)

if chunker.chunk: # is there anything left?
    print ''.join(chunker.chunk)

Ausgabe:

abc
def
gh

Andere Tipps

Wenn Sie eine Liste in Scheiben teilen möchten, können Sie diesen Trick verwenden:

list_of_slices = zip(*(iter(the_list),) * slice_size)

Zum Beispiel

>>> zip(*(iter(range(10)),) * 3)
[(0, 1, 2), (3, 4, 5), (6, 7, 8)]

Wenn die Anzahl der Elemente ist durch die Scheibe Größe nicht teilbare und Sie die Liste mit None-Pad, dies zu tun:

>>> map(None, *(iter(range(10)),) * 3)
[(0, 1, 2), (3, 4, 5), (6, 7, 8), (9, None, None)]

Es ist ein schmutziger Trick


OK, ich werde erklären, wie es funktioniert. Es wird schwierig sein, zu erklären, aber ich werde mein Bestes versuchen.

Zuerst ein wenig Hintergrund:

In Python Sie eine Liste mit einer Zahl wie folgt multiplizieren kann:

[1, 2, 3] * 3 -> [1, 2, 3, 1, 2, 3, 1, 2, 3]
([1, 2, 3],) * 3 -> ([1, 2, 3], [1, 2, 3], [1, 2, 3])

Und ein Iterator Objekt kann wie folgt einmal verbraucht werden :

>>> l=iter([1, 2, 3])
>>> l.next()
1
>>> l.next()
2
>>> l.next()
3

Die zip Funktion gibt eine Liste von Tupeln, wobei das i-te Tupel enthält das i-te Element von jedem der Argument-Sequenzen oder Iterables. Zum Beispiel:

zip([1, 2, 3], [20, 30, 40]) -> [(1, 20), (2, 30), (3, 40)]
zip(*[(1, 20), (2, 30), (3, 40)]) -> [[1, 2, 3], [20, 30, 40]]

Die * vor zip auspacken Argumente verwendet. Sie können weitere Informationen hier finden. So

zip(*[(1, 20), (2, 30), (3, 40)])

ist eigentlich äquivalent zu

zip((1, 20), (2, 30), (3, 40))

aber arbeitet mit einer variablen Anzahl von Argumenten

Nun zurück zum Trick:

list_of_slices = zip(*(iter(the_list),) * slice_size)

iter(the_list) -> konvertiert die Liste in ein Iterator

(iter(the_list),) * N -.> Wird ein N Verweis auf the_list Iterator erzeugen

zip(*(iter(the_list),) * N) -> wird diese Liste von Iteratoren in zip-Feed. Was wiederum Gruppe sie in N Größe Tupel. Da aber alle N Elemente in der Tat Hinweise auf die gleiche Iterator iter(the_list) sind das Ergebnis Anrufe next() auf dem ursprünglichen Iterator wiederholt werden

Ich hoffe, dass es erklärt. Ich rate Ihnen eine leichter zu gehen Lösung zu verstehen. Ich habe nur versucht, diesen Trick zu erwähnen, weil ich mag es.

Wenn Sie jede iterable konsumieren können Sie diese Funktionen nutzen können:

from itertools import chain, islice

def ichunked(seq, chunksize):
    """Yields items from an iterator in iterable chunks."""
    it = iter(seq)
    while True:
        yield chain([it.next()], islice(it, chunksize-1))

def chunked(seq, chunksize):
    """Yields items from an iterator in list chunks."""
    for chunk in ichunked(seq, chunksize):
        yield list(chunk)

Wollen Sie damit sagen etwas wie:

def callonslices(size, fatherList, foo):
  for i in xrange(0, len(fatherList), size):
    foo(fatherList[i:i+size])

Wenn dies in etwa die Funktionalität ist, dass Sie möchten, dass Sie vielleicht, wenn Sie es wünschen, kleiden sie ein bisschen in einem Generator auf:

def sliceup(size, fatherList):
  for i in xrange(0, len(fatherList), size):
    yield fatherList[i:i+size]

und dann:

def callonslices(size, fatherList, foo):
  for sli in sliceup(size, fatherList):
    foo(sli)

Verwenden Sie einen Generator:

big_list = [1,2,3,4,5,6,7,8,9]
slice_length = 3
def sliceIterator(lst, sliceLen):
    for i in range(len(lst) - sliceLen + 1):
        yield lst[i:i + sliceLen]

for slice in sliceIterator(big_list, slice_length):
    foo(slice)

sliceIterator implementiert ein "Schiebefenster" der Breite sliceLen über die squence lst, dh es erzeugt überlappende Scheiben: [1,2,3], [2,3,4], [3,4,5], .. . Nicht sicher, ob das die Absicht der ist OP, though.

Ich bin nicht sicher, aber es scheint, Sie wollen das tun, was einen gleitenden Durchschnitt genannt wird. numpy bietet die Möglichkeit für diese (die convolve-Funktion).

>>> x = numpy.array(range(20))
>>> x
    array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16,
       17, 18, 19])    
>>> n = 2 # moving average window
>>> numpy.convolve(numpy.ones(n)/n, x)[n-1:-n+1]
array([  0.5,   1.5,   2.5,   3.5,   4.5,   5.5,   6.5,   7.5,   8.5,
         9.5,  10.5,  11.5,  12.5,  13.5,  14.5,  15.5,  16.5,  17.5,  18.5])

Das Schöne daran ist, dass es schön verschiedene Gewichtungsschemata empfängt (nur ändern numpy.ones(n) / n auf etwas anderes).

Sie können eine komplette Material finden Sie hier: http://www.scipy.org/Cookbook/SignalSmooth

Ihre Frage könnte etwas ausführlicher verwenden, aber wie:

def iterate_over_slices(the_list, slice_size):
    for start in range(0, len(the_list)-slice_size):
        slice = the_list[start:start+slice_size]
        foo(slice)

Für einen nahezu Einzeiler (nach itertools Import) in der Vene von Nadjas Antwort Umgang mit nicht-Chunk teilbar Größen ohne padding:

>>> import itertools as itt
>>> chunksize = 5
>>> myseq = range(18)
>>> cnt = itt.count()
>>> print [ tuple(grp) for k,grp in itt.groupby(myseq, key=lambda x: cnt.next()//chunksize%2)]
[(0, 1, 2, 3, 4), (5, 6, 7, 8, 9), (10, 11, 12, 13, 14), (15, 16, 17)]

Wenn Sie möchten, können Sie von der itertools.count() Anforderung loszuwerden enumerate() verwenden, mit einem eher hässlichen:

[ [e[1] for e in grp] for k,grp in itt.groupby(enumerate(myseq), key=lambda x: x[0]//chunksize%2) ]

(In diesem Beispiel wird die enumerate() wäre überflüssig, aber nicht alle Sequenzen sind ordentlich Bereiche wie diese, natürlich)

Bei weitem nicht so sauber, wie einige anderen Antworten, aber nützlich in einer Prise, vor allem, wenn bereits den Import itertools.

Die Erweiterung auf die Antwort von @Ants Aasma: In Python 3.7 die Handhabung der StopIteration Ausnahme geändert (entsprechend PEP-479 ) . Eine kompatible Version wäre:

from itertools import chain, islice

def ichunked(seq, chunksize):
    it = iter(seq)
    while True:
        try:
            yield chain([next(it)], islice(it, chunksize - 1))
        except StopIteration:
            return
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top