Iteración sobre las rebanadas de la lista
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:
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