Wie indiziere ich in Python eine Liste mit einer anderen Liste?

130

Ich möchte eine Liste mit einer anderen Liste wie dieser indizieren

L = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
Idx = [0, 3, 7]
T = L[ Idx ]

und T sollte eine Liste sein, die ['a', 'd', 'h'] enthält.

Gibt es einen besseren Weg als

T = []
for i in Idx:
    T.append(L[i])

print T
# Gives result ['a', 'd', 'h']
Daniel Andrén
quelle

Antworten:

241
T = [L[i] for i in Idx]
van
quelle
6
Ist das schneller als eine for-Schleife oder nur kürzer?
Daniel Andrén
9
@ Daniel: beide + empfohlen
SilentGhost
13
Ein schneller Timing-Test (kein Pysco oder so, machen Sie es so, wie Sie wollen) zeigte, dass das Listenverständnis 2,5-mal schneller ist als die Schleife (1000 Elemente, 10000-mal wiederholt).
James Hopkin
2
(Die Verwendung von Karte und Lambda ist noch langsamer - zu erwarten, da für jede Iteration eine Funktion aufgerufen wird)
James Hopkin
+1 Wenn die Indizierungsliste willkürlich ist, ist eine Listenkomprimierung der Weg. Ich denke jedoch, dass Scheiben, wenn möglich, was hier nicht der Fall zu sein scheint, noch schneller sind.
Jaime
40

Wenn Sie Numpy verwenden, können Sie das erweiterte Schneiden folgendermaßen durchführen:

>>> import numpy
>>> a=numpy.array(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'])
>>> Idx = [0, 3, 7]
>>> a[Idx]
array(['a', 'd', 'h'], 
      dtype='|S1')

... und ist wahrscheinlich viel schneller (wenn die Leistung ausreicht, um sich um den Numpy-Import zu kümmern)

Paul
quelle
5
Mein schneller Timeit-Test hat gezeigt, dass die Verwendung von np.array tatsächlich fast dreimal langsamer ist (einschließlich der Konvertierung in ein Array).
Andrzej Pronobis
Es funktioniert besser, wenn Sie es sowieso für Array-Operationen konvertieren müssen. Zu zeitaufwändig für regelmäßige Listenoperationen.
Frankliuao
9

Ein funktionaler Ansatz:

a = [1,"A", 34, -123, "Hello", 12]
b = [0, 2, 5]

from operator import itemgetter

print(list(itemgetter(*b)(a)))
[1, 34, 12]
Padraic Cunningham
quelle
Dies funktioniert nicht, wenn bnur ein Element enthalten ist.
Blhsing
7
T = map(lambda i: L[i], Idx)
Mehrdad Afshari
quelle
6
musste in Liste in py3k konvertiert werden
SilentGhost
5

Ich war mit keinem dieser Ansätze zufrieden und habe eine FlexlistKlasse entwickelt, die eine flexible Indizierung ermöglicht, entweder nach Ganzzahl, Slice oder Indexliste:

class Flexlist(list):
    def __getitem__(self, keys):
        if isinstance(keys, (int, slice)): return list.__getitem__(self, keys)
        return [self[k] for k in keys]

Was Sie für Ihr Beispiel verwenden würden als:

L = Flexlist(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'])
Idx = [0, 3, 7]
T = L[ Idx ]

print(T)  # ['a', 'd', 'h']
jedwards
quelle
Dies zeigt auch die Leistungsfähigkeit und Flexibilität von Python!
Crowie
Es ist so einfach, dies auch für vorhandenen Code zu erweitern. Rufen Sie einfach an existing_list = Flexlist(existing_list)und wir haben die erforderliche Funktionalität, ohne Code zu
beschädigen
1
L= {'a':'a','d':'d', 'h':'h'}
index= ['a','d','h'] 
for keys in index:
    print(L[keys])

Ich würde eine Verwendung Dict addgewünscht keyszuindex

user4749532
quelle
0

Sie können die __getitem__Methode auch mapwie folgt kombinieren :

L = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
Idx = [0, 3, 7]
res = list(map(L.__getitem__, Idx))
print(res)
# ['a', 'd', 'h']
David S.
quelle