2010-09-09 25 views
14

mi pregunta es, ¿tengo una lista como la siguiente:lista multidimensional de Python ... ¿cómo tomar una dimensión?

someList = [[0,1,2],[3,4,5],[6,7,8]] 

cómo iba a conseguir la primera entrada de cada sublista?

Sé que podría hacer esto:

newList = [] 
for entry in someList: 
    newList.append(entry[0]) 

donde newList sería:

[0, 3, 6] 

Pero hay una manera de hacer algo como:

newList = someList[:][0] 

?

EDIT:

La eficiencia es de gran preocupación. De hecho, estoy pasando por una lista que cuenta con más de 300.000 entradas

Respuesta

17

EDITAR: ¡Aquí hay algunos números reales! El izip, la comprensión de listas y numpy formas de hacerlo tienen la misma velocidad.

# zip 
>>> timeit.timeit("newlist = zip(*someList)[0]", setup = "someList = [range(1000000), range(1000000), range(1000000)]", number = 10) 
1.4984046398561759 

# izip 
>>> timeit.timeit("newlist = izip(*someList).next()", setup = "someList = range(1000000), range(1000000), range(1000000)]; from itertools import izip", number = 10) 
2.2186223645803693e-05 

# list comprehension 
>>> timeit.timeit("newlist = [li[0] for li in someList]", setup = "someList = [range(1000000), range(1000000), range(1000000)]", number = 10) 
1.4677040212518477e-05 

# numpy 
>>> timeit.timeit("newlist = someList[0,:]", setup = "import numpy as np; someList = np.array([range(1000000), range(1000000), range(1000000)])", number = 10) 
6.6217344397045963e-05 
>>> 

Para grandes estructuras de datos como este se debe utilizar numpy, que implementes un tipo de matriz en C y por lo tanto es significativamente más eficiente. También proporciona toda la manipulación de matrices que siempre desearás.

>>> import numpy as np 
>>> foo = np.array([[0,1,2],[3,4,5],[6,7,8]]) 
>>> foo[:,0] 
array([0, 3, 6]) 

También puede transponer ...

>>> foo.transpose() 
array([[0, 3, 6], 
     [1, 4, 7], 
     [2, 5, 8]]) 

... trabajo con matrices n-dimensionales ...

>>> foo = np.zeros((3,3,3)) 
>>> foo 
array([[[ 0., 0., 0.], 
     [ 0., 0., 0.], 
     [ 0., 0., 0.]], 

     [[ 0., 0., 0.], 
     [ 0., 0., 0.], 
     [ 0., 0., 0.]], 

     [[ 0., 0., 0.], 
     [ 0., 0., 0.], 
     [ 0., 0., 0.]]]) 
>>> foo[0,...] 
array([[ 0., 0., 0.], 
     [ 0., 0., 0.], 
     [ 0., 0., 0.]]) 

..do álgebra lineal eficiente ...

>>> foo = no.ones((3,3)) 
>>> np.linalg.qr(foo) 
(array([[-0.57735027, 0.81649658, 0.  ], 
     [-0.57735027, -0.40824829, -0.70710678], 
     [-0.57735027, -0.40824829, 0.70710678]]), array([[ -1.73205081e+00, -1. 
73205081e+00, -1.73205081e+00], 
     [ 0.00000000e+00, -1.57009246e-16, -1.57009246e-16], 
     [ 0.00000000e+00, 0.00000000e+00, 0.00000000e+00]])) 

... y básicamente hacen anything that Matlab can.

+0

WOW, muchas gracias. Esto es SUPER RÁPIDO en comparación con otras soluciones. Si pudiera +100000, lo haría – Richard

+1

@Richard: Eso depende ... cuanto más grande es la lista, mejor se desempeñan las soluciones de comprensión de listas y listas contra numpy, porque no consideran la gran mayoría de las entradas de la matriz. –

+2

@jellybean: dudo que ... numpy esté bastante bien optimizado. Creo que es seguro decir que un simple corte en columnas no leerá toda la matriz. (Aunque, por supuesto, puedo estar equivocado, no conozco los detalles de implementación de C.) De hecho, creo que 'numpy' debería funcionar * mejor * con una lista más grande, a medida que comienza la sobrecarga de la' lista' nativa de Python para agregar. ¡Pero por supuesto, solo hay una forma de averiguarlo! – katrielalex

8
zip(*someList)[0] 

EDIT:

En respuesta al comentario de recursiva: También se podría utilizar

from itertools import izip 
izip(*someList).next() 

para un mejor rendimiento.

Algunos análisis de tiempo:

python -m timeit "someList = [range(1000000), range(1000000), range(1000000)]; newlist = zip(*someList)[0]" 
10 loops, best of 3: 498 msec per loop 
python -m timeit "someList = [range(1000000), range(1000000), range(1000000)]; from itertools import izip; newlist = izip(*someList).next()" 
10 loops, best of 3: 111 msec per loop 
python -m timeit "someList = [range(1000000), range(1000000), range(1000000)]; newlist = [li[0] for li in someList]" 
10 loops, best of 3: 110 msec per loop 

Así IZIP y el juego lista por comprensión en la misma liga.

Por supuesto, la comprensión de la lista es más flexible cuando se necesita un índice distinto de 0, y es más explícito.

Edit2:

Incluso la solución numpy no es tan rápido (pero que podría haber elegido un ejemplo no representativa):

python -m timeit "import numpy as np; someList = np.array([range(1000000), range(1000000), range(1000000)]); newList = someList[:,0]" 
10 loops, best of 3: 551 msec per loop 
+0

Si someList es grande, esto va a hacer un montón de trabajo innecesario, al combinar todas las otras columnas también. – recursive

10

Caso perfecto para una list comprehension:

[sublist[0] for sublist in someList] 

Dado que la eficiencia es una preocupación importante, esto será mucho más rápido que el enfoque zip. Dependiendo de lo que está haciendo con el resultado, es posible que pueda conseguir aún más la eficiencia mediante el uso del enfoque de expresión generadora:

(sublist[0] for sublist in someList) 

Tenga en cuenta que esto devuelve un generador en lugar de una lista, sin embargo, por lo que no puede ser indexado en.

Cuestiones relacionadas