Extrae el primer elemento de cada sublista

146

Me pregunto cuál es la mejor manera de extraer el primer elemento de cada sublista en una lista de listas y agregarlo a una nueva lista. Entonces si tengo:

lst = [[a,b,c], [1,2,3], [x,y,z]]

y quiero sacar a, 1y xy crear una lista separada de aquellos.

Lo intenté:

lst2.append(x[0] for x in lst)
Konrad
fuente
1
Tu código es casi correcto. El único problema es el uso de la comprensión de la lista.
Abhishek Mittal

Respuestas:

198

Usando la comprensión de la lista :

>>> lst = [['a','b','c'], [1,2,3], ['x','y','z']]
>>> lst2 = [item[0] for item in lst]
>>> lst2
['a', 1, 'x']
alecxe
fuente
El método de comprensión de listas también es el más rápido, incluso más rápido que el método de Numpy. La respuesta de jboi habla sobre la comparación de rendimiento,
Qiao Zhang
83

Puedes usar zip:

>>> lst=[[1,2,3],[11,12,13],[21,22,23]]
>>> zip(*lst)[0]
(1, 11, 21)

O, Python 3 donde zipno produce una lista:

>>> list(zip(*lst))[0]
(1, 11, 21)

O,

>>> next(zip(*lst))
(1, 11, 21)

O (mi favorito) usa numpy:

>>> import numpy as np
>>> a=np.array([[1,2,3],[11,12,13],[21,22,23]])
>>> a
array([[ 1,  2,  3],
       [11, 12, 13],
       [21, 22, 23]])
>>> a[:,0]
array([ 1, 11, 21])
perro
fuente
No se ha votado a favor, pero el primer fragmento de código (el zip) produce: "el objeto 'zip' no es subscriptable". Python 3.6 en Jupyter.
jboi
@jboi: solo envuélvelo listprimero o úsalo next. Gracias
dawg
20

Tuve el mismo problema y sentí curiosidad por el rendimiento de cada solución.

Aquí está el %timeit:

import numpy as np
lst = [['a','b','c'], [1,2,3], ['x','y','z']]

El primer numpy-way, transformando la matriz:

%timeit list(np.array(lst).T[0])
4.9 µs ± 163 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

Totalmente nativo usando la comprensión de la lista (como lo explica @alecxe):

%timeit [item[0] for item in lst]
379 ns ± 23.1 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

Otra forma nativa de usar zip(como explica @dawg):

%timeit list(zip(*lst))[0]
585 ns ± 7.26 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

Segunda forma numpy. También explicado por @dawg:

%timeit list(np.array(lst)[:,0])
4.95 µs ± 179 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

Sorprendentemente (bueno, al menos para mí) la forma nativa que usa la comprensión de listas es la más rápida y aproximadamente 10 veces más rápida que la forma numpy. Ejecutar las dos formas de numpy sin el final listahorra aproximadamente un µs que todavía está en la diferencia de 10x.

Tenga en cuenta que, cuando rodeé cada fragmento de código con una llamada a len, para asegurarme de que los Generadores funcionen hasta el final, el tiempo se mantuvo igual.

jboi
fuente
44
Hay una sobrecarga considerable al crear una matriz.
hpaulj
1
de acuerdo con hpaulj, si comienza con una matriz numpy, [:, 0] es más rápido. Pruébalo: lst = np.array ([['' a ',' b ',' c '], [1,2,3], [' x ',' y ',' z ']]), entonces lst [:, 0]. La conversión en las contrarreloj de ejemplo le da a la comprensión de la lista una ventaja injusta. Entonces, si puede, use una matriz numpy para almacenar sus datos si la velocidad es su objetivo final. Numpy es casi siempre más rápido. Está construido para la velocidad.
spacedustpi
13

Python incluye una función llamada itemgetter para devolver el elemento en un índice específico en una lista:

from operator import itemgetter

Pase la función itemgetter () al índice del elemento que desea recuperar. Para recuperar el primer elemento, usaría itemgetter (0). Lo importante a entender es que itemgetter (0) en sí mismo devuelve una función. Si pasa una lista a esa función, obtendrá el elemento específico:

itemgetter(0)([10, 20, 30]) # Returns 10

Esto es útil cuando lo combina con map (), que toma una función como primer argumento, y una lista (o cualquier otro iterable) como segundo argumento. Devuelve el resultado de llamar a la función en cada objeto en el iterable:

my_list = [['a', 'b', 'c'], [1, 2, 3], ['x', 'y', 'z']]
list(map(itemgetter(0), my_list)) # Returns ['a', 1, 'x']

Tenga en cuenta que map () devuelve un generador, por lo que el resultado se pasa a list () para obtener una lista real. En resumen, su tarea podría hacerse así:

lst2.append(list(map(itemgetter(0), lst)))

Este es un método alternativo al uso de una comprensión de lista, y qué método elegir depende en gran medida del contexto, la legibilidad y la preferencia.

Más información: https://docs.python.org/3/library/operator.html#operator.itemgetter

Christian Abbott
fuente
2

Tu código es casi correcto. El único problema es el uso de la comprensión de la lista.

Si usa like: (x [0] para x en lst), devuelve un objeto generador. Si usa like: [x [0] para x en lst], devuelve una lista.

Cuando agrega el resultado de la comprensión de la lista a una lista, el resultado de la comprensión de la lista es el elemento único de la lista.

lst = [["a","b","c"], [1,2,3], ["x","y","z"]]
lst2 = []
lst2.append([x[0] for x in lst])
print lst2[0]

lst2 = [['' a ', 1,' x ']]

lst2 [0] = ['a', 1, 'x']

Avísame si soy incorrecto.

Abhishek Mittal
fuente
1
lst = [['a','b','c'], [1,2,3], ['x','y','z']]
outputlist = []
for values in lst:
    outputlist.append(values[0])

print(outputlist) 

Salida: ['a', 1, 'x']

PrabhuPrakash
fuente
0

Dijiste que tienes una lista existente. Entonces iré con eso.

>>> lst1 = [['a','b','c'], [1,2,3], ['x','y','z']]
>>> lst2 = [1, 2, 3]

En este momento está agregando el objeto generador a su segunda lista.

>>> lst2.append(item[0] for item in lst)
>>> lst2
[1, 2, 3, <generator object <genexpr> at 0xb74b3554>]

Pero probablemente quieras que sea una lista de los primeros elementos

>>> lst2.append([item[0] for item in lst])
>>> lst2
[1, 2, 3, ['a', 1, 'x']]

Ahora agregamos la lista de primeros elementos a la lista existente. Si desea agregar los elementos por sí mismos, no una lista de ellos, a los existentes, usaría list.extend. En ese caso, no tenemos que preocuparnos de agregar un generador, porque extender lo usará para agregar cada elemento que obtenga de allí, para extender la lista actual.

>>> lst2.extend(item[0] for item in lst)
>>> lst2
[1, 2, 3, 'a', 1, 'x']

o

>>> lst2 + [x[0] for x in lst]
[1, 2, 3, 'a', 1, 'x']
>>> lst2
[1, 2, 3]

https://docs.python.org/3.4/tutorial/datastructures.html#more-on-lists https://docs.python.org/3.4/tutorial/datastructures.html#list-comprehensions

Hendrik
fuente
1
Su respuesta es agradable y completa para lo que parece que el OP quiere, pero creo que la palabra appenden la pregunta está causando confusión. Parece que simplemente quiere la parte de comprensión de la lista de su solución.
beroe