Jak w Pythonie indeksować listę z inną listą?

130

Chciałbym zindeksować listę z inną taką listą

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

a T powinno być listą zawierającą [„a”, „d”, „h”].

Czy jest lepszy sposób niż

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

print T
# Gives result ['a', 'd', 'h']
Daniel Andrén
źródło

Odpowiedzi:

241
T = [L[i] for i in Idx]
awangarda
źródło
7
Czy jest to szybsze niż pętla for, czy tylko krótsze?
Daniel Andrén
10
@daniel: oba + zalecane
SilentGhost
14
Szybki test synchronizacji (bez pysco lub cokolwiek innego, więc zrób z tego, co chcesz) pokazał zrozumienie listy 2,5 razy szybciej niż pętla (1000 elementów, powtórzone 10000 razy).
James Hopkin
2
(użycie mapy i lambdy jest jeszcze wolniejsze - należy się spodziewać, ponieważ wywołuje funkcję dla każdej iteracji)
James Hopkin
+1 Jeśli lista indeksowana jest dowolna, właściwym rozwiązaniem jest jej kompresja. Myślę jednak, że jeśli to możliwe, co wydaje się nie mieć miejsca, plasterki są jeszcze szybsze.
Jaime
41

Jeśli używasz numpy, możesz wykonać rozszerzone cięcie w ten sposób:

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

... i prawdopodobnie jest znacznie szybszy (jeśli wydajność jest wystarczająca, aby zawracać sobie głowę importem numpy)

Paweł
źródło
5
Mój test quick timeit pokazał, że użycie np.array jest właściwie prawie 3 razy wolniejsze (łącznie z konwersją do array).
Andrzej Pronobis
Działa lepiej, jeśli i tak musisz przekonwertować go na operacje tablicowe. Zbyt czasochłonne w przypadku zwykłych operacji na listach.
frankliuao
9

Podejście funkcjonalne:

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
źródło
To nie zadziała, jeśli bzdarzy się, że zawiera tylko jeden element.
blhsing
7
T = map(lambda i: L[i], Idx)
Mehrdad Afshari
źródło
6
trzeba było przekonwertować na listę w py3k
SilentGhost
5

Nie byłem zadowolony z żadnego z tych podejść, więc wymyśliłem Flexlistklasę, która pozwala na elastyczne indeksowanie według liczby całkowitej, wycinka lub listy indeksów:

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

Które, na przykład, użyłbyś jako:

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

print(T)  # ['a', 'd', 'h']
jedwards
źródło
co również demonstruje moc i elastyczność Pythona!
crowie
Tak łatwo jest to rozszerzyć również dla istniejącego kodu. Po prostu zadzwoń existing_list = Flexlist(existing_list)i mamy wymaganą funkcjonalność bez łamania kodu
Yesh
1
L= {'a':'a','d':'d', 'h':'h'}
index= ['a','d','h'] 
for keys in index:
    print(L[keys])

Chciałbym użyć Dict addpożądane keys, abyindex

user4749532
źródło
0

Możesz również użyć __getitem__metody połączonej z mapnastępującymi:

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.
źródło