2010-12-21 11 views
16

Lo opuesto al aplanamiento de la lista.Creación de sublistas

Dada una lista y una longitud n devuelve una lista de sublistas de longitud n.

def sublist(lst, n): 
    sub=[] ; result=[] 
    for i in lst: 
     sub+=[i] 
     if len(sub)==n: result+=[sub] ; sub=[] 
    if sub: result+=[sub] 
    return result 

Un ejemplo:

Si la lista es:

[1,2,3,4,5,6,7,8] 

y N es:

3 

de devolución:

[[1, 2, 3], [4, 5, 6], [7, 8]] 

¿Hay alguna forma más elocuente/concisa?

un aparte, lo que se prefiere al anexar listas a listas (en el contexto anterior):

list1+=[list2] 

O:

list1.append(list2) 

Dado que (de acuerdo con 'Programación en Python 3' de Summerfeild) ¿ellos son lo mismo?

Gracias.

Respuesta

15

Tal lista de listas podría construirse usando un list comprehension:

In [17]: seq=[1,2,3,4,5,6,7,8] 
In [18]: [seq[i:i+3] for i in range(0,len(seq),3)] 
Out[18]: [[1, 2, 3], [4, 5, 6], [7, 8]] 

También existe la grouper idiom:

In [19]: import itertools 
In [20]: list(itertools.izip_longest(*[iter(seq)]*3)) 
Out[20]: [(1, 2, 3), (4, 5, 6), (7, 8, None)] 

pero tenga en cuenta que los elementos que faltan se rellenan con el valor Ninguno. izip_longest puede tomar un parámetro fillvalue si se desea algo diferente de None.


list1+=[list2] - señalando los soportes de este tiempo - es equivalente a list1.append(list2). Mi prioridad más alta al escribir el código es la legibilidad, no la velocidad. Por esta razón, iría con list1.append(list2). La legibilidad es subjetiva, sin embargo, y probablemente esté influenciada en gran medida por los modismos con los que está familiarizado.

Felizmente, en este caso, la legibilidad y la velocidad parecen coincidir:

In [41]: %timeit list1=[1,2,3]; list1.append(list2) 
1000000 loops, best of 3: 612 ns per loop 

In [42]: %timeit list1=[1,2,3]; list1+=[list2] 
1000000 loops, best of 3: 847 ns per loop 
+0

Gracias unutbu, tengo que reírme de lo trivial que es usar la lista de comprensión. Subraya mi necesidad de estudiarlos. En cuanto a + = vs append, entiendo la diferencia, notando que comparé list1 + = [list2] con list1.append (list2), not list1 + = list2 y list1.append (list2). Gracias excelente respuesta/discusión. –

+0

@Michael Puckett: Vaya, leí mal la segunda parte de su pregunta. Editando ... – unutbu

+0

Gracias unutbu - append ftw. :) –

1

creo que esta función de división hace lo que usted está buscando (aunque funciona con cualquier iterador en lugar de listas):

from itertools import islice 

def take(n, it): 
    "Return first n items of the iterable as a list" 
    return list(islice(it, n)) 

def split(it, size): 
    it = iter(it) 
    size = int(size) 
    ret = take(size, it) 
    while ret: 
     yield ret 
     ret = take(size, it) 

Editar: En cuanto a su asside, yo siempre uso list.append (bla), ya que me parece más idiomático, pero creo que son funcionalmente equivalentes.

+2

las cosas django no se ve necesario –

+0

@Xavier yup, lo he quitado (originalmente estaba usando esto como un filtro de plantilla django) –

+0

Gracias Gabriel. –

6

¿Qué hay de lo siguiente (donde x es su lista):

[x[i:i+3] for i in range(0, len(x), 3)] 

Esto es trivial para generalizar para n!=3 .

En cuanto a su segunda pregunta, son equivalentes, así que creo que es una cuestión de estilo. Sin embargo, asegúrese de que no esté confusing append with extend.

+0

Gracias aix, lista de comprensión definitivamente el camino a seguir. Estoy disgustado, no pensé en ello, pero me consuela saber que soy un novato de pitón. –

5

Esta función puede tomar cualquier tipo de iterable (no sólo las secuencias de longitud conocida):

import itertools 

def grouper(n, it): 
    "grouper(3, 'ABCDEFG') --> ABC DEF G" 
    it = iter(it) 
    return iter(lambda: list(itertools.islice(it, n)), []) 

print(list(grouper(3, [1,2,3,4,5,6,7,8,9,10]))) 
# [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]] 
+0

gracias tokland, es bueno saberlo. –

0

que sé, se ve como un brainfuck, pero es obras:

>>> a = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15] 
>>> n = 3 
>>> [i for j in [[a[t:t+n] for x in a[:1:t+1] if (t%n)==False] for t in range(len(a))] for i in j] 
[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12], [13, 14, 15]] 

>>> n = 4 
>>> [i for j in [[a[t:t+n] for x in a[:1:t+1] if (t%n)==False] for t in range(len(a))] for i in j] 
[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15]] 
0

Para algunos casos específicos, podría ser útil usar el paquete numpy. En este paquete usted tiene una rutina reshape:

import numpy as np 
x = np.array([1,2,3,4,5,6]) 
np.reshape(x, (-1,3)) 

Sin embargo, esta solución no engrosar su lista, si no es una multiplicación de n.

+0

Numpy es un poco exagerado para esto. SIN EMBARGO, es bueno saber sobre la funcionalidad señalada. Gracias joker5. –

2

¿Has oído hablar de boltons?

Boltons es un conjunto de utilidades de Python puros en el mismo espíritu que - y sin embargo notoriamente ausente de - la la biblioteca estándar

Tiene lo que quiere, incorporado, llamado chunked

from boltons import iterutils 

iterutils.chunked([1,2,3,4,5,6,7,8], 3) 

salida:

[[1, 2, 3], [4, 5, 6], [7, 8]] 

Y lo que es más atractivo en boltons es que tiene chunked como un iterador , llamados chunked_iter, por lo que no es necesario para almacenar toda la cosa en la memoria. Limpio, ¿verdad?

Cuestiones relacionadas