web-dev-qa-db-fra.com

Obtenir une sous-liste d'une liste Python, avec les indices donnés?

J'ai une liste Python, dites a = [0,1,2,3,4,5,6]. J'ai également une liste d'indices, par exemple b = [0,2,4,5]. Comment obtenir la liste des éléments de a avec des indices dans b?

22
becko

Vous pouvez utiliser la compréhension de la liste pour obtenir cette liste:

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

Cela équivaut à:

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

Sortie:

[0,2,4,5]

Remarque:

N'oubliez pas que some_list[index] est la notation utilisée pour accéder à un élément d'un list dans un index spécifique.

34
Christian

Quelque chose de différent...

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

La fonction itemgetter prend une ou plusieurs clés comme arguments et retourne une fonction qui renverra les éléments aux clés données dans son argument. Donc, dans ce qui précède, nous créons une fonction qui renverra les éléments à l'index 0, l'index 2, l'index 4 et l'index 5, puis appliquer cette fonction à a.

Il semble être un peu plus rapide que la compréhension de liste équivalente

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

Quant à savoir pourquoi itemgetter est plus rapide, la compréhension doit exécuter des codes d'octets supplémentaires Python.

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

Alors que itemgetter est un seul appel implémenté 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
22
chepner

Si vous êtes fan de programmation fonctionnelle , vous pouvez utiliser map et list.__getitem__ :

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

L'approche de compréhension de liste est plus canonique dans Python cependant ...

8
iCodez

Un peu de comparaison de vitesse pour toutes les méthodes mentionnées et d'autres de dictionnaire Python: obtenir la liste des valeurs pour la liste des clés :

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

Le plus rapide est donc f = operator.itemgetter(*idx); f(l)

3
Sklavit

De nombreuses solutions proposées produiront un KeyError si b contient un index non présent dans a. Les éléments suivants ignoreront les index non valides si vous le souhaitez.

>>> 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 produit des tuples de paires index/valeur. Puisque nous avons à la fois l'élément et son index, nous pouvons vérifier la présence de l'index dans b

3
Brian

En utilisant List Comprehension , cela devrait fonctionner -

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

Tester cela -

>>> 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]
2
Kamehameha

En utilisant numpy.asarray. Numpy permet d'obtenir un sous-tableau de tableau par liste d'indices.

>>> 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]
1
Temak

Encore une autre alternative pour de meilleures performances si cela est important pour vous - ce n'est en aucun cas le plus Pythonic mais je suis presque sûr que c'est le plus efficace:

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

Remarque: Vous n'avez pas besoin de convertir en list en Python 2. Cependant, vous le faites en Python À partir de 3 ans (si de futurs visiteurs peuvent avoir un problème similaire).

1
Alex Thornton