Як в індексації списку іншим списком в Python?


130

Я хотів би проіндексувати список із іншим подібним списком

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

і T повинен стати списком, що містить ['a', 'd', 'h'].

Чи є кращий спосіб, ніж

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

print T
# Gives result ['a', 'd', 'h']

Відповіді:


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

7
Це швидше, ніж фор-петля або лише коротше?
Даніель Андрен

10
@daniel: обидва + рекомендовано
SilentGhost

14
Швидкий тест на встановлення часу (жодного pysco чи нічого, тому зробіть з нього те, що ви хочете) показав розуміння списку в 2,5 рази швидше, ніж цикл (1000 елементів, повторений 10000 разів).
Джеймс Хопкін

2
(використання карти та лямбда ще повільніше - можна очікувати, оскільки вона викликає функцію для кожної ітерації)
Джеймс Хопкін

+1 Якщо список індексації є довільним, то шляхом розширення списку є спосіб. Я думаю, що, коли це можливо, що, здається, не так, шматочки ще швидше.
Хайме

41

Якщо ви використовуєте numpy, ви можете виконати розширені нарізки так:

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

... і, ймовірно, набагато швидше (якщо продуктивність достатньо турботи, щоб зайнятися нудним імпортом)


5
Мій швидкий тест timeit показав, що використання np.array насправді майже в 3 рази повільніше (включаючи перетворення в масив).
Анджей Пронобіс

Він працює краще, якщо вам потрібно перетворити його для операцій з масивом. Занадто багато часу для регулярних операцій зі списком.
frankliuao

9

Функціональний підхід:

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

from operator import itemgetter

print(list(itemgetter(*b)(a)))
[1, 34, 12]

Це не спрацює, якщо bтрапляється лише один елемент.
блхзінг


5

Я не був задоволений жодним із цих підходів, тому придумав Flexlistклас, який дозволяє здійснювати гнучку індексацію за цілим числом, фрагментом або індексним списком:

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

Який, для вашого прикладу, ви б використовували як:

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

print(T)  # ['a', 'd', 'h']

що також демонструє силу та гнучкість Python!
groie

Це так просто розширити і на існуючий код. Просто зателефонуйте, existing_list = Flexlist(existing_list)і ми маємо необхідну функціональність, не порушуючи жодного коду
Yesh

1
L= {'a':'a','d':'d', 'h':'h'}
index= ['a','d','h'] 
for keys in index:
    print(L[keys])

Я хотів би використовувати Dict addбажано , keysщобindex


0

Ви також можете використовувати __getitem__метод, поєднаний із mapтаким, як:

L = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
Idx = [0, 3, 7]
res = list(map(L.__getitem__, Idx))
print(res)
# ['a', 'd', 'h']
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.