web-dev-qa-db-fra.com

Accéder à plusieurs éléments de la liste en connaissant leur index

Je dois choisir des éléments dans la liste donnée, en connaissant leur index. Supposons que je souhaite créer une nouvelle liste, qui contient un élément d'indice 1, 2, 5, à partir de la liste donnée [-2, 1, 5, 3, 8, 5, 6]. Ce que j'ai fait c'est:

a = [-2,1,5,3,8,5,6]
b = [1,2,5]
c = [ a[i] for i in b]

Y a-t-il une meilleure façon de le faire? quelque chose comme c = a [b]?

186
hoang tran

Vous pouvez utiliser operator.itemgetter :

_from operator import itemgetter 
a = [-2, 1, 5, 3, 8, 5, 6]
b = [1, 2, 5]
print(itemgetter(*b)(a))
# Result:
(1, 5, 5)
_

Ou vous pouvez utiliser numpy :

_import numpy as np
a = np.array([-2, 1, 5, 3, 8, 5, 6])
b = [1, 2, 5]
print(list(a[b]))
# Result:
[1, 5, 5]
_

Mais vraiment, votre solution actuelle est satisfaisante. C'est probablement le plus intéressant de tous.

178
TerryA

Alternatives:

>>> map(a.__getitem__, b)
[1, 5, 5]

>>> import operator
>>> operator.itemgetter(*b)(a)
(1, 5, 5)
41
falsetru

Une autre solution pourrait être via pandas Series:

import pandas as pd

a = pd.Series([-2, 1, 5, 3, 8, 5, 6])
b = [1, 2, 5]
c = a[b]

Vous pouvez ensuite reconvertir c en liste si vous voulez:

c = list(c)
6
BossaNova

Tests basiques et peu exhaustifs comparant le temps d'exécution des cinq réponses fournies:

def numpyIndexValues(a, b):
    na = np.array(a)
    nb = np.array(b)
    out = list(na[nb])
    return out

def mapIndexValues(a, b):
    out = map(a.__getitem__, b)
    return list(out)

def getIndexValues(a, b):
    out = operator.itemgetter(*b)(a)
    return out

def pythonLoopOverlap(a, b):
    c = [ a[i] for i in b]
    return c

multipleListItemValues = lambda searchList, ind: [searchList[i] for i in ind]

en utilisant l'entrée suivante:

a = range(0, 10000000)
b = range(500, 500000)

la boucle simple python était la plus rapide, l'opération lambda étant une seconde proche, mapIndexValues ​​et getIndexValues ​​étaient toujours assez similaires avec la méthode numpy nettement plus lente après la conversion des listes en tableaux numpy. La conversion numpy.array supprimée est la plus rapide.

numpyIndexValues -> time:1.38940598 (when converted the lists to numpy arrays)
numpyIndexValues -> time:0.0193445 (using numpy array instead of python list as input, and conversion code removed)
mapIndexValues -> time:0.06477512099999999
getIndexValues -> time:0.06391049500000001
multipleListItemValues -> time:0.043773591
pythonLoopOverlap -> time:0.043021754999999995
4
Don Smythe

Je suis sûr que cela a déjà été pris en compte: si la quantité d'indices dans b est petite et constante, on pourrait simplement écrire le résultat comme:

c = [a[b[0]]] + [a[b[1]]] + [a[b[2]]]

Ou encore plus simple si les indices eux-mêmes sont des constantes ...

c = [a[1]] + [a[2]] + [a[5]]

Ou s'il y a une plage d'indices consécutive ...

c = a[1:3] + [a[5]]
2
ecp

Ma réponse n'utilise pas les collections numpy ou python.

Une façon triviale de trouver des éléments serait la suivante:

a = [-2, 1, 5, 3, 8, 5, 6]
b = [1, 2, 5]
c = [i for i in a if i in b]

Inconvénient: cette méthode peut ne pas fonctionner pour des listes plus volumineuses. L'utilisation de numpy est recommandée pour des listes plus volumineuses.

0
Lavya 'Orion'

Index statiques et petite liste?

N'oubliez pas que si la liste est petite et que les index ne changent pas, comme dans votre exemple, la meilleure chose à faire est parfois d'utiliser décompression de séquence :

_,a1,a2,_,_,a3,_ = a

Les performances sont bien meilleures et vous pouvez également enregistrer une ligne de code:

 %timeit _,a1,b1,_,_,c1,_ = a
10000000 loops, best of 3: 154 ns per loop 
%timeit itemgetter(*b)(a)
1000000 loops, best of 3: 753 ns per loop
 %timeit [ a[i] for i in b]
1000000 loops, best of 3: 777 ns per loop
 %timeit map(a.__getitem__, b)
1000000 loops, best of 3: 1.42 µs per loop
0
G M