¿Obtener una lista secundaria de una lista de Python, con los índices dados?

Tengo una lista de Python, digamos a = [0,1,2,3,4,5,6] . También tengo una lista de índices, digamos b = [0,2,4,5] . ¿Cómo puedo obtener la lista de elementos de a con índices en b ?

Puedes usar la lista de comprensión para obtener esa lista:

 c = [a[index] for index in b] print c 

Esto es equivalente a:

 c= [] for index in b: c.append(a[index]) print c 

Salida:

 [0,2,4,5] 

Nota:

Recuerde que some_list[index] es la notación utilizada para acceder a un elemento de una list en un índice específico.

Algo diferente…

 >>> a = range(7) >>> b = [0,2,4,5] >>> import operator >>> operator.itemgetter(*b)(a) (0, 2, 4, 5) 

La función itemgetter toma una o más claves como argumentos y devuelve una función que devolverá los elementos a las claves indicadas en su argumento. Así que en lo anterior, creamos una función que devolverá los elementos en el índice 0, el índice 2, el índice 4 y el índice 5, luego aplicamos esa función a a .

Parece ser un poco más rápido que la lista de comprensión equivalente

 In [1]: import operator In [2]: a = range(7) In [3]: b = [0,2,4,5] In [4]: %timeit operator.itemgetter(*b)(a) 1000000 loops, best of 3: 388 ns per loop In [5]: %timeit [ a[i] for i in b ] 1000000 loops, best of 3: 415 ns per loop In [6]: f = operator.itemgetter(*b) In [7]: %timeit f(a) 10000000 loops, best of 3: 183 ns per loop 

En cuanto a por itemgetter es más rápido el itemgetter , la comprensión tiene que ejecutar códigos de bytes de Python adicionales.

 In [3]: def f(a,b): return [a[i] for i in b] In [4]: def g(a,b): return operator.itemgetter(*b)(a) In [5]: dis.dis(f) 1 0 BUILD_LIST 0 3 LOAD_FAST 1 (b) 6 GET_ITER >> 7 FOR_ITER 16 (to 26) 10 STORE_FAST 2 (i) 13 LOAD_FAST 0 (a) 16 LOAD_FAST 2 (i) 19 BINARY_SUBSCR 20 LIST_APPEND 2 23 JUMP_ABSOLUTE 7 >> 26 RETURN_VALUE 

Mientras que itemgetter es una única llamada implementada en C:

 In [6]: dis.dis(g) 1 0 LOAD_GLOBAL 0 (operator) 3 LOAD_ATTR 1 (itemgetter) 6 LOAD_FAST 1 (b) 9 CALL_FUNCTION_VAR 0 12 LOAD_FAST 0 (a) 15 CALL_FUNCTION 1 18 RETURN_VALUE 

Si eres un fanático de la progtwigción funcional , puedes usar map y list.__getitem__ :

 >>> a = [0,1,2,3,4,5,6] >>> b = [0,2,4,5] >>> map(a.__getitem__, b) [0, 2, 4, 5] >>> 

El enfoque de comprensión de listas es más canónico en Python, aunque …

Muchas de las soluciones propuestas producirán un KeyError si b contiene un índice que no está presente en a . Lo siguiente saltará índices no válidos si se desea.

 >>> b = [0,2,4,5] >>> a = [0,1,2,3,4,5,6] >>> [x for i,x in enumerate(a) if i in b] [0, 2, 4, 5] >>> b = [0,2,4,500] >>> [x for i,x in enumerate(a) if i in b] [0, 2, 4] 

enumerate produce tuplas de índice, pares de valores. Como tenemos tanto el elemento como su índice, podemos verificar la presencia del índice en b

Una pequeña comparación de velocidad para todos los métodos mencionados y otros del diccionario de Python: Obtenga una lista de valores para una lista de claves :

 Python 2.7.11 |Anaconda 2.4.1 (64-bit)| (default, Jan 19 2016, 12:08:31) [MSC v.1500 64 bit (AMD64)] on win32 In[2]: import numpy.random as nprnd idx = nprnd.randint(1000, size=10000) l = nprnd.rand(1000).tolist() from operator import itemgetter import operator f = operator.itemgetter(*idx) %timeit f(l) %timeit list(itemgetter(*idx)(l)) %timeit [l[_] for _ in idx] # list comprehension %timeit map(l.__getitem__, idx) %timeit list(l[_] for _ in idx) # a generator expression passed to a list constructor. %timeit map(lambda _: l[_], idx) # using 'map' %timeit [x for i, x in enumerate(l) if i in idx] %timeit filter(lambda x: l.index(x) in idx, l) # UPDATE @Kundor: work only for list with unique elements 10000 loops, best of 3: 175 µs per loop 1000 loops, best of 3: 707 µs per loop 1000 loops, best of 3: 978 µs per loop 1000 loops, best of 3: 1.03 ms per loop 1000 loops, best of 3: 1.18 ms per loop 1000 loops, best of 3: 1.86 ms per loop 100 loops, best of 3: 12.3 ms per loop 10 loops, best of 3: 21.2 ms per loop 

Así que el más rápido es f = operator.itemgetter(*idx); f(l) f = operator.itemgetter(*idx); f(l)

Usando List Comprehension , esto debería funcionar –

 li = [a[i] for i in b] 

Probando esto

 >>> a = [0,10,20,30,40,50,60] >>> b = [0,2,4,5] >>> li = [a[i] for i in b] >>> li [0, 20, 40, 50] 

Otra alternativa para un mejor rendimiento si eso es importante para usted, no es de ninguna manera la más Pythonic, pero estoy bastante seguro de que es la más eficiente:

 >>> list(filter(lambda x: a.index(x) in b, a)) [0, 2, 4, 5] 

Nota: no es necesario que se convierta a una list en Python 2. Sin embargo, sí lo hace en Python 3 en adelante (si algún visitante futuro puede tener un problema similar).

Utilizando numpy.asarray . Numpy permite obtener subarray de matriz por lista de índices.

 >>> import numpy as np >>> a = [0,10,20,30,40,50,60] >>> b = [0,2,4,5] >>> res = np.asarray(a)[b].tolist() >>> res [0, 20, 40, 50]