Sélectionner explicitement des éléments dans une liste ou un tuple


120

J'ai la liste Python suivante (peut également être un tuple):

myList = ['foo', 'bar', 'baz', 'quux']

je peux dire

>>> myList[0:3]
['foo', 'bar', 'baz']
>>> myList[::2]
['foo', 'baz']
>>> myList[1::2]
['bar', 'quux']

Comment sélectionner explicitement des éléments dont les index n'ont pas de modèles spécifiques? Par exemple, je veux sélectionner [0,2,3]. Ou parmi une très grande liste de 1000 articles, je veux sélectionner [87, 342, 217, 998, 500]. Y a-t-il une syntaxe Python qui fait cela? Quelque chose qui ressemble à:

>>> myBigList[87, 342, 217, 998, 500]

1
Cela semble être un doublon. L'autre question a plus de votes, mais cela semble avoir une meilleure réponse avec les horaires.
AnnanFay

Réponses:


150
list( myBigList[i] for i in [87, 342, 217, 998, 500] )

J'ai comparé les réponses avec python 2.5.2:

  • 19,7 usec: [ myBigList[i] for i in [87, 342, 217, 998, 500] ]

  • 20,6 usec: map(myBigList.__getitem__, (87, 342, 217, 998, 500))

  • 22,7 usec: itemgetter(87, 342, 217, 998, 500)(myBigList)

  • 24,6 usec: list( myBigList[i] for i in [87, 342, 217, 998, 500] )

Notez que dans Python 3, le 1er a été changé pour être le même que le 4ème.


Une autre option serait de commencer par un numpy.arrayqui permet l'indexation via une liste ou un numpy.array:

>>> import numpy
>>> myBigList = numpy.array(range(1000))
>>> myBigList[(87, 342, 217, 998, 500)]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: invalid index
>>> myBigList[[87, 342, 217, 998, 500]]
array([ 87, 342, 217, 998, 500])
>>> myBigList[numpy.array([87, 342, 217, 998, 500])]
array([ 87, 342, 217, 998, 500])

Le tuplene fonctionne pas de la même manière que ce sont des tranches.


2
De préférence sous forme de liste [myBigList[i] for i in [87, 342, 217, 998, 500]], mais j'aime bien cette approche.
zeekay

@MedhatHelmy C'est déjà dans la réponse. La troisième option utilisée from operator import itemgetterdans la partie initialisation de python -mtimeit.
Dan D.

Je me demande, juste du point de vue de la conception du langage, pourquoi myBigList[(87, 342, 217, 998, 500)]ne fonctionne pas quand myBigListun python ordinaire list? Quand j'essaye que je reçois TypeError: list indices must be integers or slices, not tuple. Ce serait tellement plus facile que de taper la compréhension - y a-t-il un problème de conception / mise en œuvre du langage?
sparc_spread

@sparc_spread, c'est parce listsqu'en Python n'acceptent que des entiers ou des tranches. La transmission d'un entier garantit qu'un seul élément est extrait d'une liste existante. Passer une tranche garantit qu'une partie de celle-ci est récupérée, mais passer un tuple revient à passer un type de données ( tuple) en tant qu'argument à un autre type de données ( list) qui est syntaxiquement incorrect.
amanb

48

Et ça:

from operator import itemgetter
itemgetter(0,2,3)(myList)
('foo', 'baz', 'quux')

2
C'est le plus sexy à ce jour. J'adore ce operatormodule!
jathanism

10

Ce n'est pas intégré, mais vous pouvez créer une sous-classe de liste qui prend les tuples comme "index" si vous le souhaitez:

class MyList(list):

    def __getitem__(self, index):
        if isinstance(index, tuple):
            return [self[i] for i in index]
        return super(MyList, self).__getitem__(index)


seq = MyList("foo bar baaz quux mumble".split())
print seq[0]
print seq[2,4]
print seq[1::2]

impression

foo
['baaz', 'mumble']
['bar', 'quux']

2
(+1) Solution soignée! Avec cette extension, la gestion des tableaux en Python commence à ressembler beaucoup à R ou Matlab.
Assad Ebrahim du

7

Peut-être qu'une liste de compréhension est dans l'ordre:

L = ['a', 'b', 'c', 'd', 'e', 'f']
print [ L[index] for index in [1,3,5] ]

Produit:

['b', 'd', 'f']

Est-ce ce que vous recherchez?


6
>>> map(myList.__getitem__, (2,2,1,3))
('baz', 'baz', 'bar', 'quux')

Vous pouvez également créer votre propre Listclasse qui prend en charge les tuples comme arguments __getitem__si vous voulez pouvoir le faire myList[(2,2,1,3)].


Bien que cela fonctionne, ce n'est généralement pas une bonne idée d'appeler directement des variables magiques. Vous feriez mieux d'utiliser une compréhension de liste ou un module d'aide comme operator.
jathanism

@jathanism: Je dois respectueusement être en désaccord. Cependant, si vous êtes préoccupé par la compatibilité ascendante (par opposition à public / privé), je peux certainement voir d'où vous venez.
ninjagecko

C'est de là que je viens. :) Suite à cela, c'est la même raison pour laquelle il vaut mieux utiliser len(myList)over myList.__len__().
jathanism

une solution créative. Je ne pense pas que ce soit une mauvaise idée d'invoquer la variable magique. le programmeur choisit sa méthode préférée en fonction des circonstances de programmation.
Jacob CUI

2

Je veux juste souligner que même la syntaxe d'itemgetter semble vraiment soignée, mais elle est un peu lente lorsqu'elle est exécutée sur une grande liste.

import timeit
from operator import itemgetter
start=timeit.default_timer()
for i in range(1000000):
    itemgetter(0,2,3)(myList)
print ("Itemgetter took ", (timeit.default_timer()-start))

Itemgetter a pris 1.065209062149279

start=timeit.default_timer()
for i in range(1000000):
    myList[0],myList[2],myList[3]
print ("Multiple slice took ", (timeit.default_timer()-start))

La tranche multiple a pris 0,6225321444745759


Premier extrait, veuillez ajouter myList = np.array(range(1000000))sinon vous obtiendrez une erreur.
Cloud Cho

1

Une autre solution possible:

sek=[]
L=[1,2,3,4,5,6,7,8,9,0]
for i in [2, 4, 7, 0, 3]:
   a=[L[i]]
   sek=sek+a
print (sek)

0

comme souvent quand vous avez un tableau numpy booléen comme mask

[mylist[i] for i in np.arange(len(mask), dtype=int)[mask]]

Un lambda qui fonctionne pour n'importe quelle séquence ou np.array:

subseq = lambda myseq, mask : [myseq[i] for i in np.arange(len(mask), dtype=int)[mask]]

newseq = subseq(myseq, mask)

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.