Wählen Sie explizit Elemente aus einer Liste oder einem Tupel aus


120

Ich habe die folgende Python-Liste (kann auch ein Tupel sein):

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

ich kann sagen

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

Wie wähle ich explizit Elemente aus, deren Indizes keine bestimmten Muster aufweisen? Zum Beispiel möchte ich auswählen [0,2,3]. Oder ich möchte aus einer sehr großen Liste von 1000 Artikeln auswählen [87, 342, 217, 998, 500]. Gibt es eine Python-Syntax, die das macht? So etwas sieht aus:

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

1
Dies scheint ein Duplikat zu sein. Die andere Frage hat mehr Stimmen, aber dies scheint eine bessere Antwort mit Timings zu haben.
AnnanFay

Antworten:


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

Ich habe die Antworten mit Python 2.5.2 verglichen:

  • 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] )

Beachten Sie, dass in Python 3 die erste geändert wurde, um mit der vierten identisch zu sein.


Eine andere Möglichkeit wäre, mit einer zu beginnen, numpy.arraydie die Indizierung über eine Liste oder eine ermöglicht 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])

Das tuplefunktioniert nicht so wie das sind Slices.


2
[myBigList[i] for i in [87, 342, 217, 998, 500]]Am liebsten als Listenkomposition, aber ich mag diesen Ansatz am besten.
Zeekay

@MedhatHelmy Das ist schon in der Antwort. Die dritte Option, die from operator import itemgetterim Initialisierungsteil von verwendet wird python -mtimeit.
Dan D.

Ich frage mich, nur aus Sicht des Sprachdesigns, warum myBigList[(87, 342, 217, 998, 500)]funktioniert es nicht, wenn myBigListes sich um eine normale Python handelt list? Wenn ich das versuche, bekomme ich TypeError: list indices must be integers or slices, not tuple. Das wäre so viel einfacher als das Verständnis abzutippen - gibt es ein Problem mit dem Sprachdesign / der Sprachimplementierung?
sparc_spread

@sparc_spread, weil listsin Python nur Ganzzahlen oder Slices akzeptiert werden. Durch Übergeben einer Ganzzahl wird sichergestellt, dass nur ein Element aus einer vorhandenen Liste abgerufen wird. Durch das Übergeben eines Slice wird sichergestellt, dass ein Teil davon abgerufen wird. Das Übergeben eines Tupels entspricht jedoch dem Übergeben eines Datentyps ( tuple) als Argument an einen anderen Datentyp ( list), der syntaktisch falsch ist.
Amanb

48

Was ist damit:

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

2
Dies ist die sexieste bisher. Ich liebe dieses operatorModul!
Nathanismus

10

Es ist nicht integriert, aber Sie können eine Unterklasse von Listen erstellen, die Tupel als "Indizes" verwendet, wenn Sie möchten:

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]

Drucken

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

2
(+1) Ordentliche Lösung! Mit dieser Erweiterung sieht die Behandlung von Arrays in Python nach R oder Matlab aus.
Assad Ebrahim

7

Vielleicht ist ein Listenverständnis angebracht:

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

Produziert:

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

Ist es das, wonach du suchst?


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

Sie können auch eine eigene ListKlasse erstellen , die Tupel als Argumente unterstützt, __getitem__wenn Sie dies möchten myList[(2,2,1,3)].


Während dies funktioniert, ist es normalerweise keine gute Idee, magische Variablen direkt aufzurufen. Verwenden Sie besser ein Listenverständnis oder ein Hilfsmodul wie operator.
Nathanismus

@jathanism: Ich muss respektvoll widersprechen. Wenn Sie sich Sorgen über die Vorwärtskompatibilität machen (im Gegensatz zu öffentlich / privat), kann ich auf jeden Fall sehen, woher Sie kommen.
Ninjagecko

Von dort komme ich. :) Danach ist es der gleiche Grund, warum es besser ist, len(myList)über zu verwenden myList.__len__().
Nathanismus

Eine kreative Lösung. Ich denke nicht, dass es eine schlechte Idee ist, eine magische Variable aufzurufen. Der Programmierer wählt seinen bevorzugten Weg basierend auf den Programmierumständen.
Jacob CUI

2

Ich möchte nur darauf hinweisen, dass selbst die Syntax von itemgetter wirklich ordentlich aussieht, aber es ist etwas langsam, wenn es auf einer großen Liste ausgeführt wird.

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 nahm 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))

Mehrere Scheiben nahmen 0,6225321444745759


Erster Ausschnitt, bitte hinzufügen, myList = np.array(range(1000000))sonst erhalten Sie eine Fehlermeldung.
Cloud Cho

1

Eine andere mögliche Lösung:

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

wie oft, wenn Sie ein boolesches numpy-Array wie haben mask

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

Ein Lambda, das für jede Sequenz oder jedes np.array funktioniert:

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

newseq = subseq(myseq, mask)

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.