2009-10-26 19 views
45

Digamos que tengo una lista de longitud arbitraria, L:forma alternativa de dividir una lista en grupos de n

L = list(range(1000)) 

¿Cuál es la mejor manera de dividir la lista en grupos de n? Esta es la mejor estructura que he sido capaz de llegar a, y por alguna razón no se siente como que es la mejor manera de llevar a cabo la tarea:

n = 25 
for i in range(0, len(L), n): 
    chunk = L[i:i+25] 

¿Hay un built-in para hacer esto ¿Estoy perdido?

Edit: Las primeras respuestas están volviendo a trabajar mi bucle for en un listcomp, que no es la idea; básicamente me estás devolviendo mi respuesta exacta en una forma diferente. Estoy viendo si hay un medio alternativo para lograr esto, como un hipotético .split en las listas o algo así. También hago utilizar esto como un generador de código que escribí anoche:

def split_list(L, n): 
    assert type(L) is list, "L is not a list" 
    for i in range(0, len(L), n): 
     yield L[i:i+n] 
+1

crear un generador para más Pythonic. Pero nosotros para mí, es el código normal :) – Oduvan

+0

Puedes crear tu propia clase para almacenar una lista y codificarla allí, entonces tendrías un enfoque más directo ... pero dudo que cambie nada. Las listas no tienen una función .split(), al menos no en Python 2.x;) – kender

+0

@Jurily Idiomías idiotónicas - http://stackoverflow.com/questions/58968/what-defines-pythonian-or-pythonic –

Respuesta

36

Un Python recipe (En Python 2.6, utilice itertools.izip_longest):

def grouper(n, iterable, fillvalue=None): 
    "grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx" 
    args = [iter(iterable)] * n 
    return itertools.zip_longest(*args, fillvalue=fillvalue) 

Ejemplo de uso:

>>> list(grouper(3, range(9))) 
[(0, 1, 2), (3, 4, 5), (6, 7, 8)] 
>>> list(grouper(3, range(10))) 
[(0, 1, 2), (3, 4, 5), (6, 7, 8), (9, None, None)] 

Si desea que el último grupo sea más corto que los otros en lugar de acolchado con fillvalue, entonces podrías, por ejemplo cambiar el código como el siguiente:

>>> def mygrouper(n, iterable): 
...  args = [iter(iterable)] * n 
...  return ([e for e in t if e != None] for t in itertools.zip_longest(*args)) 
... 
>>> list(mygrouper(3, range(9))) 
[[0, 1, 2], [3, 4, 5], [6, 7, 8]] 
>>> list(mygrouper(3, range(10))) 
[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]] 
+0

Aceptado porque llegó primero. No estoy seguro de cuál es más Pythonic, ya que la legibilidad también es importante; sin embargo, esta pregunta presentó algunas buenas alternativas. –

+3

Si la lista actual tenía None en algún punto intermedio, tu última función también eliminaría esas. – cnu

+0

Esto hace una suposición sobre la implementación de zip_longest (es decir, que visita los iterables estrictamente en orden en un bucle) que podría no ser estrictamente seguro. Probablemente sea seguro de usar, pero un poco de olor. –

33

¿Qué tal:

>>> n = 2 
>>> l = [1,2,3,4,5,6,7,8,9] 
>>> [ l[i:i+n] for i in range(0, len(l), n) ] 
[[1, 2], [3, 4], [5, 6], [7, 8], [9]] 
+0

Consulte mi edición más reciente. –

+2

Agradable. Prefiero este, mucho mejor que zip para mi caso de uso. – cedbeu

+0

Esta puede no ser la forma más rápida de hacerlo, pero seguro que es la más pitónica. – seriousdev

7
n = 25  
list_of_lists = [L[i:i+n] for i in range(0, len(L), n)] 

le da la lista de listas [[0..24], [25..49], ..]

Si len(L) % n no es 0, el último elemento (list_of_lists[-1]) durará len (L)% n.

+0

Ver mi edición más reciente. –

-1

Y si la forma que elija sus principales intereses, random.sample (población, k), devolver una lista k longitud de elementos únicos elegidos de la secuencia de la población. Usado para muestreo aleatorio sin reemplazo.

+0

No veo cómo responde esto a la pregunta. –

88

Aquí van:

list_of_groups = zip(*(iter(the_list),) * group_size) 

Ejemplo:

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

Si el número de elementos no es divisible por N, pero todavía quiere incluirlos puede utilizar izip_longest pero sólo está disponible desde python 2.6

El resultado es un generador, por lo que debe convertirlo en una lista si quieres imprimirlo

Finalmente, si no tiene python 2.6 y pegado con una versión más antigua, pero aún quieren tener el mismo resultado se puede utilizar el mapa:

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

me gustaría añadir un poco de comparación de velocidad entre los diferentes métodos presentados hasta el momento:

python -m timeit -s 'from itertools import izip_longest; L = range(1000)' 'list(izip_longest(*(iter(L),) * 3))' 
10000 loops, best of 3: 47.1 usec per loop 

python -m timeit -s 'L = range(1000)' 'zip(*(iter(L),) * 3)' 
10000 loops, best of 3: 50.1 usec per loop 

python -m timeit -s 'L = range(1000)' 'map(None, *(iter(L),) * 3)' 
10000 loops, best of 3: 50.7 usec per loop 

python -m timeit -s 'L = range(1000)' '[L[i:i+3] for i in range(0, len(L), 3)]' 
10000 loops, best of 3: 157 usec per loop 

python -m timeit -s 'import itertools; L = range(1000)' '[list(group) for key, group in itertools.groupby(L, lambda k: k//3)]' 
1000 loops, best of 3: 1.41 msec per loop 

la lista por comprensión y el grupo por métodos son claramente más lento de lo postal, izip_longest y mapa

+6

Tus habilidades de Python me asustan un poco. :) ¡Buena respuesta! –

+3

Esta debería ser la respuesta aceptada. No podía recordar el mapa y las expresiones idiomáticas para esto, aunque recordé que eran la forma "correcta" y esto surgió en una búsqueda web, gracias. –

+0

+1 para puntos de referencia en todas las soluciones. Eso es algo que las personas extrañan mucho en Python responde, y como se ve, hace una gran diferencia el método que utiliza. –

12

itertools.groupby es una herramienta bien, aquí hay una manera de dividir una lista de números enteros simplemente usando división entera:

>>> for key, group in itertools.groupby(range(10), lambda k: k//3): 
... print key, list(group) 
... 
0 [0, 1, 2] 
1 [3, 4, 5] 
2 [6, 7, 8] 
3 [9] 

(La lista tiene que comenzar con 0 a comenzar con un grupo completo.)

0

He aquí la versión recursividad. Es ineficiente porque Python tiene límites de recursión, pero esta versión ilustra que cada tarea se puede resolver a través de la recursión.

def split_to_groups(l, n): 
    assert (len(l)/n) < 998, "Can't split to {} groups".format(len(l)/n) 
    if l == []: 
     return [] 
    else: 
     f = [l[:n]] 
     f.extend(split_to_groups(l[n:], n)) 
     return f 
Cuestiones relacionadas