En Python, ¿cómo indexo una lista con otra lista?

130

Me gustaría indexar una lista con otra lista como esta

L = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
Idx = [0, 3, 7]
T = L[ Idx ]

y T debería terminar siendo una lista que contiene ['a', 'd', 'h'].

¿Hay una mejor manera que

T = []
for i in Idx:
    T.append(L[i])

print T
# Gives result ['a', 'd', 'h']
Daniel Andrén
fuente

Respuestas:

241
T = [L[i] for i in Idx]
camioneta
fuente
77
¿Es esto más rápido que un bucle for o solo más corto?
Daniel Andrén
10
@daniel: ambos + recomendado
SilentGhost
14
Una prueba de sincronización rápida (sin pysco ni nada, así que haga lo que quiera) mostró la comprensión de la lista 2.5 veces más rápido que el ciclo (1000 elementos, repetidos 10000 veces).
James Hopkin
2
(usando un mapa y lambda es aún más lento - es de esperar, ya que llama a una función para cada iteración)
James Hopkin
+1 Si la lista de indexación es arbitraria, entonces la comprensión de la lista es el camino. Sin embargo, creo que, cuando sea posible, lo que parece no ser el caso aquí, los cortes son aún más rápidos.
Jaime
41

Si está usando numpy, puede realizar un corte extendido así:

>>> import numpy
>>> a=numpy.array(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'])
>>> Idx = [0, 3, 7]
>>> a[Idx]
array(['a', 'd', 'h'], 
      dtype='|S1')

... y probablemente sea mucho más rápido (si el rendimiento es una preocupación suficiente para molestarse con la importación numpy)

Pablo
fuente
55
Mi prueba rápida de timeit mostró que usar np.array es en realidad casi 3 veces más lento (incluida la conversión a matriz).
Andrzej Pronobis
Funciona mejor si necesita convertirlo para operaciones de matriz de todos modos. Demasiado tiempo para las operaciones regulares de la lista.
frankliuao
9

Un enfoque funcional:

a = [1,"A", 34, -123, "Hello", 12]
b = [0, 2, 5]

from operator import itemgetter

print(list(itemgetter(*b)(a)))
[1, 34, 12]
Padraic Cunningham
fuente
Esto no funcionará si bcontiene solo un elemento.
blhsing
7
T = map(lambda i: L[i], Idx)
Mehrdad Afshari
fuente
66
necesaria para ser convertidos a la lista en py3k
SilentGhost
5

No estaba contento con ninguno de estos enfoques, por lo que se me ocurrió una Flexlistclase que permite una indexación flexible, ya sea por entero, por segmento o por índice:

class Flexlist(list):
    def __getitem__(self, keys):
        if isinstance(keys, (int, slice)): return list.__getitem__(self, keys)
        return [self[k] for k in keys]

Que, por ejemplo, usarías como:

L = Flexlist(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'])
Idx = [0, 3, 7]
T = L[ Idx ]

print(T)  # ['a', 'd', 'h']
jedwards
fuente
que también demuestra el poder y la flexibilidad de Python!
crowie
Es muy fácil extender esto también para el código existente. Simplemente llame existing_list = Flexlist(existing_list)y tenemos la funcionalidad requerida sin descifrar ningún código
Yesh
1
L= {'a':'a','d':'d', 'h':'h'}
index= ['a','d','h'] 
for keys in index:
    print(L[keys])

Yo usaría un Dict adddeseado keysparaindex

usuario4749532
fuente
0

También puede usar el __getitem__método combinado con maplo siguiente:

L = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
Idx = [0, 3, 7]
res = list(map(L.__getitem__, Idx))
print(res)
# ['a', 'd', 'h']
David S
fuente