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

Odpowiedzi:


241
T = [L[i] for i in Idx]

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)


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]

To nie zadziała, jeśli bzdarzy się, że zawiera tylko jeden element.
blhsing


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

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


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']
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.