Pregunta

Quiero un algoritmo para iterar sobre las rebanadas de la lista. tamaño rebanadas se establece fuera de la función y puede diferir.

En mi mente, es algo como:

for list_of_x_items in fatherList:
    foo(list_of_x_items)

¿Hay una manera de definir adecuadamente list_of_x_items o alguna otra forma de hacer esto utilizando Python 2.5?


edit1: Aclaración Ambos términos "y" ventana deslizante "partición" suenan aplicable a mi tarea, pero no soy un experto. Así que voy a explicar el problema un poco más profundo y añadir a la pregunta:

El fatherList es un numpy.array multinivel que estoy recibiendo de un archivo. La función tiene que encontrar los promedios de la serie (el usuario proporciona la longitud de la serie) para promediar estoy usando la función mean(). Ahora para la expansión pregunta:

Edit2: Cómo modificar la función que ha proporcionado para almacenar los artículos adicionales y utilizarlos cuando el próximo fatherList se alimenta a la función

?

por ejemplo, si la lista es de longitud 10 y el tamaño de un trozo es 3, entonces el décimo miembro de la lista se almacena y se añade al principio de la lista siguiente.


Relacionado con:

¿Fue útil?

Solución

respuesta a la última parte de la pregunta:

  

Actualización pregunta: ¿Cómo modificar la   función que ha proporcionado para almacenar   los elementos adicionales y utilizarlos cuando el   siguiente fatherList se alimenta a la   función?

Si necesita almacenar el estado entonces usted puede utilizar un objeto para eso.

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 = [] 

Ejemplo:

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)

Salida:

abc
def
gh

Otros consejos

Si desea dividir una lista en rodajas puede utilizar este truco:

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

Por ejemplo

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

Si el número de elementos no es divisible por el tamaño de segmento y desea para rellenar la lista con Nada se puede hacer esto:

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

Es un pequeño truco sucio


OK, voy a explicar cómo funciona. Va a ser difícil de explicar, pero voy a tratar lo mejor posible.

Primero un poco de historia:

En Python se puede multiplicar una lista de una serie como esta:

[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])

Y un objeto iterador se puede consumir una vez como esto :

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

El href="http://docs.python.org/library/functions.html#zip" zip función devuelve una lista de tuplas, en donde la i-ésima tupla contiene el elemento i-ésimo de cada una de las secuencias de argumentos o iterables. Por ejemplo:

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]]

El * delante de cremallera utilizado para desempaquetar argumentos. Puede encontrar más detalles href="http://docs.python.org/tutorial/controlflow.html#unpacking-argument-lists" aquí . Así

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

es en realidad equivalente a

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

pero funciona con un número variable de argumentos

Ahora, de vuelta al truco:

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

iter(the_list) -> convertir la lista en un iterador

(iter(the_list),) * N -> generará una referencia N para la_lista iterador

.

zip(*(iter(the_list),) * N) -> va a alimentar a los iteradores en lista de cremallera. Que a su vez les agrupará en N dimensionada tuplas. Pero ya que todos los artículos N son de hecho referencias a la misma iterador iter(the_list) el resultado se repite llamadas a next() en el iterador originales

Espero que lo explica todo. Le aconsejo que se vaya con una solución más fácil de entender. Sólo la tentación de hablar de este truco porque me gusta.

Si usted quiere ser capaz de consumir cualquier iterable puede utilizar estas funciones:

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)

¿Quieres decir algo como:

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

Si esto es más o menos la funcionalidad que desee que podría, si lo desea, vestido, en un poco de un generador:

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

y, a continuación:

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

Utilice un generador:

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 implementa una "ventana deslizante" de sliceLen anchura sobre el lst squence, es decir, que produce rebanadas que se superponen: [1,2,3], [2,3,4], [3,4,5], .. . No estoy seguro si esto es la intención de la OP, sin embargo.

No estoy seguro, pero parece que quiere hacer lo que se llama una media móvil. numpy proporciona instalaciones de (la función de convolución).

>>> 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])

Lo bueno es que tiene capacidad para diferentes sistemas de ponderación muy bien (sólo cambia numpy.ones(n) / n a otra cosa).

Puede encontrar un material completo aquí: http://www.scipy.org/Cookbook/SignalSmooth

Su pregunta podría utilizar algo más de detalle, pero ¿qué hay de:

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)

En un casi un trazador de líneas (después de la importación itertools) en la vena de la respuesta de Nadia hacer frente a la no-Chunk tamaños divisibles sin relleno:

>>> 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)]

Si lo desea, puede deshacerse del requisito itertools.count() usando enumerate(), con un lugar más feo:

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

(En este ejemplo el enumerate() sería superfluo, pero no todas las secuencias son rangos de ordenadas como este, obviamente)

No está tan limpio como algunas otras respuestas, pero útil en caso de necesidad, especialmente si ya importar itertools.

Ampliando la respuesta de @Ants Aasma: En Python 3.7 el manejo de la excepción StopIteration cambió (de acuerdo con PEP-479 ) . Una versión compatible sería:

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
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top