¿Cómo extraer los elementos n-ésimo de una lista de tuplas?


112

Estoy tratando de obtener los elementos n-ésimo de una lista de tuplas.

Tengo algo como:

elements = [(1,1,1),(2,3,7),(3,5,10)]

Deseo extraer solo los segundos elementos de cada tupla en una lista:

seconds = [1, 3, 5]

Sé que se podría hacer con un forbucle, pero quería saber si hay otra forma, ya que tengo miles de tuplas.

Respuestas:


185
n = 1 # N. . .
[x[n] for x in elements]

34

Esto también funciona:

zip(*elements)[1]

(Principalmente estoy publicando esto, para demostrarme a mí mismo que he asimilado zip...)

Véalo en acción:

>>> help(zip)

Ayuda sobre la función incorporada zip en el módulo incorporado :

Código Postal(...)

zip (seq1 [, seq2 [...]]) -> [(seq1 [0], seq2 [0] ...), (...)]

Devuelve una lista de tuplas, donde cada tupla contiene el elemento i-ésimo de cada una de las secuencias de argumentos. La lista devuelta se trunca a la longitud de la secuencia de argumentos más corta.

>>> elements = [(1,1,1),(2,3,7),(3,5,10)]
>>> zip(*elements)
[(1, 2, 3), (1, 3, 5), (1, 7, 10)]
>>> zip(*elements)[1]
(1, 3, 5)
>>>

Lo bueno que aprendí hoy: usar *listen argumentos para crear una lista de parámetros para una función ...

Nota : En Python3, zipdevuelve un iterador, por lo que en su lugar utilícelo list(zip(*elements))para devolver una lista de tuplas.


2
y utilizar **dictpara crear argumentos de palabras clave: def test(foo=3, bar=3): return foo*barluegod = {'bar': 9, 'foo'=12}; print test(**d)
— Wayne Werner

@Wayne Werner: Sí. Todo esto era conocimiento pasivo (no lo uso a menudo), pero es bueno que se lo recuerden de vez en cuando para saber dónde / qué buscar ...
— Daren Thomas

1
La verdadera historia - Me parece que en todo lo que uso con bastante frecuencia (Python, vim), que tienden a recordatorios necesidad de / frío ordenada características que he olvidado porque no los uso que a menudo.
— Wayne Werner

la sintaxis * list es bastante útil. ¿Alguna idea de dónde se describe esto en la documentación oficial de Python?
— user1748155

Solo lo encontré en el tutorial: docs.python.org/2/tutorial/…
— Daren Thomas

30

Sé que se podría hacer con un FOR pero quería saber si hay otra forma

Hay otra forma. También puedes hacerlo con map y itemgetter :

>>> from operator import itemgetter
>>> map(itemgetter(1), elements)

Sin embargo, esto todavía realiza un bucle internamente y es un poco más lento que la comprensión de la lista:

setup = 'elements = [(1,1,1) for _ in range(100000)];from operator import itemgetter'
method1 = '[x[1] for x in elements]'
method2 = 'map(itemgetter(1), elements)'

import timeit
t = timeit.Timer(method1, setup)
print('Method 1: ' + str(t.timeit(100)))
t = timeit.Timer(method2, setup)
print('Method 2: ' + str(t.timeit(100)))

Resultados:

Método 1: 1.25699996948
Método 2: 1.46600008011

Si necesita iterar sobre una lista, entonces forestá bien usar a .


2
Una pequeña adición: en python-3.x, el punto de referencia mostrará que el mapa solo toma una fracción de milisegundo. Eso es porque devolverá un iterador. method2 = 'list (map (itemgetter (1), elements))' muestra el comportamiento anterior.
— Maik Beckmann

12

Encontré esto mientras buscaba cuál es la forma más rápida de extraer el segundo elemento de una lista de 2 tuplas. No es lo que quería, pero ejecuté la misma prueba que se muestra con un tercer método más probar el método zip

setup = 'elements = [(1,1) for _ in range(100000)];from operator import itemgetter'
method1 = '[x[1] for x in elements]'
method2 = 'map(itemgetter(1), elements)'
method3 = 'dict(elements).values()'
method4 = 'zip(*elements)[1]'

import timeit
t = timeit.Timer(method1, setup)
print('Method 1: ' + str(t.timeit(100)))
t = timeit.Timer(method2, setup)
print('Method 2: ' + str(t.timeit(100)))
t = timeit.Timer(method3, setup)
print('Method 3: ' + str(t.timeit(100)))
t = timeit.Timer(method4, setup)
print('Method 4: ' + str(t.timeit(100)))

Method 1: 0.618785858154
Method 2: 0.711684942245
Method 3: 0.298138141632
Method 4: 1.32586884499

Entonces, más del doble de rápido si tiene un par de 2 tuplas para convertirlo en un dict y tomar los valores.


Esto es probablemente obvio, pero mencionaría dict(elements).values()que resultará en un dict de un elemento en lugar de una lista de comprahension o map. Esto es exactamente lo que quería (estaba interesado en parejas únicas) (+1 y muchas gracias por publicar), pero otros podrían preguntarse por qué dict es más rápido: no está asignando memoria sino solo verificando el elemento existente.
— Greg0ry

6

Tiempos de Python 3.6 para extraer el segundo elemento de una lista de 2 tuplas.

Además, se agregó el numpymétodo de matriz, que es más simple de leer (pero posiblemente más simple que la comprensión de la lista).

from operator import itemgetter
elements = [(1,1) for _ in range(100000)]

%timeit second = [x[1] for x in elements]
%timeit second = list(map(itemgetter(1), elements))
%timeit second = dict(elements).values()
%timeit second = list(zip(*elements))[1]
%timeit second = np.array(elements)[:,1]

y los tiempos:

list comprehension:  4.73 ms ± 206 µs per loop
list(map):           5.3 ms ± 167 µs per loop
dict:                2.25 ms ± 103 µs per loop
list(zip)            5.2 ms ± 252 µs per loop
numpy array:        28.7 ms ± 1.88 ms per loop

Tenga en cuenta eso map()y zip()ya no devuelva una lista, de ahí la conversión explícita.



1

Usando islicey chain.from_iterable:

>>> from itertools import chain, islice
>>> elements = [(1,1,1),(2,3,7),(3,5,10)]
>>> list(chain.from_iterable(islice(item, 1, 2) for item in elements))
[1, 3, 5]

Esto puede resultar útil cuando necesite más de un elemento:

>>> elements = [(0, 1, 2, 3, 4, 5), 
                (10, 11, 12, 13, 14, 15), 
                (20, 21, 22, 23, 24, 25)]
>>> list(chain.from_iterable(islice(tuple_, 2, 5) for tuple_ in elements))
[2, 3, 4, 12, 13, 14, 22, 23, 24]
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.