2013-08-16 1 views
112

Мне нужно выбрать некоторые элементы из данного списка, зная их индекс. Предположим, что я хотел бы создать новый список, содержащий элемент с индексом 1, 2, 5 из данного списка [-2, 1, 5, 3, 8, 5, 6]. Что я сделал:Доступ к нескольким элементам списка, зная их индекс

a = [-2,1,5,3,8,5,6] 
b = [1,2,5] 
c = [ a[i] for i in b] 

Есть ли лучший способ сделать это? что-то вроде c = a [b]?

+0

, кстати, я нашел другое решение здесь , Я еще не тестировал его, но я думаю, что могу опубликовать его здесь, когда вы заинтересованы в http://code.activestate.com/recipes/577953-get-multiple-elements-from-a-list/ –

+0

Это такое же решение, как указано в вопросе, но завернутое в функцию лямбда. –

+0

Возможный дубликат [как извлечь элементы из списка в python?] (Https://stackoverflow.com/questions/2621674/how-to-extract-elements-from-a-list-in-python) – jdhao

ответ

113

Вы можете использовать operator.itemgetter:

from operator import itemgetter 
a = [-2, 1, 5, 3, 8, 5, 6] 
b = [1, 2, 5] 
print itemgetter(*b)(a) 
# Result: 
(1, 5, 5) 

Или вы можете использовать numpy:

import numpy as np 
a = np.array([-2, 1, 5, 3, 8, 5, 6]) 
b = [1, 2, 5] 
print list(a[b]) 
# Result: 
[1, 5, 5] 

Но на самом деле, ваше текущее решение в порядке. Вероятно, это самый лучший из всех.

+14

+1 отметив, что 'c = [a [i] для i в b]' отлично. Обратите внимание, что решение 'itemgetter' не будет делать то же самое, если b имеет менее 2 элементов. – flornquake

+0

** Сторона ** ** Примечание **: Использование _itemgetter_ при работе в многопроцессорном режиме не работает. Numpy отлично работает в многопроцессорном режиме. –

+0

Дополнительный комментарий: 'a [b]' работает ** только **, когда 'a' является ** numpy ** массивом, т. Е. Вы создаете его с помощью функции numpy. –

22

Альтернативы:

>>> map(a.__getitem__, b) 
[1, 5, 5] 

>>> import operator 
>>> operator.itemgetter(*b)(a) 
(1, 5, 5) 
0

Мой ответ не использует коллекции numpy или python.

Один тривиальный способ найти элементы будут выглядеть следующим образом:

a = [-2, 1, 5, 3, 8, 5, 6] 
b = [1, 2, 5] 
c = [i for i in a if i in b] 

Минус: Этот метод не может работать для больших списков. Использование numpy рекомендуется для больших списков.

+3

Не нужно итерации 'a'. '[a [i] для i в b]' – falsetru

+0

Этот метод даже не работает ни в одном другом случае. Что, если 'a' было еще 5? – TerryA

+0

IMO, быстрее выполнить этот вид пересечения с помощью [sets] (https://docs.python.org/3/tutorial/datastructures.html#sets) – sirgogo

3

Basic и не очень обширное тестирование сравнения времени выполнения пяти поставленных ответов:

def numpyIndexValues(a, b): 
    na = np.array(a) 
    nb = np.array(b) 
    out = list(na[nb]) 
    return out 

def mapIndexValues(a, b): 
    out = map(a.__getitem__, b) 
    return list(out) 

def getIndexValues(a, b): 
    out = operator.itemgetter(*b)(a) 
    return out 

def pythonLoopOverlap(a, b): 
    c = [ a[i] for i in b] 
    return c 

multipleListItemValues = lambda searchList, ind: [searchList[i] for i in ind] 

используя следующий вход:

a = range(0, 10000000) 
b = range(500, 500000) 

простой цикл питон был самым быстрым с работы лямбда-а close second, mapIndexValues ​​и getIndexValues ​​были последовательно похожи на метод numpy значительно медленнее после преобразования списков в массивы numpy. Если данные уже находятся в массивах numpy, метод numpyIndexValues ​​с numpy преобразование .array удалено быстрее.

numpyIndexValues -> time:1.38940598 (when converted the lists to numpy arrays) 
numpyIndexValues -> time:0.0193445 (using numpy array instead of python list as input, and conversion code removed) 
mapIndexValues -> time:0.06477512099999999 
getIndexValues -> time:0.06391049500000001 
multipleListItemValues -> time:0.043773591 
pythonLoopOverlap -> time:0.043021754999999995 
+0

Я не знаю, какой интерпретатор Python вы используете, но первый метод ' numpyIndexValues' не работает, поскольку 'a',' b' имеют тип 'range'. Я предполагаю, что вы сначала конвертируете 'a',' b' в 'numpy.ndarrays'? – strpeter

+0

@ strpeter Да, я не сравнивал яблоки с яблоками, я создал массивы numpy в качестве входных данных в тестовом примере для numpyIndexValues. Я исправил это сейчас, и все они используют те же списки, что и вход. –

2

Я уверен, что это уже считается: если сумма индексов в б мала и постоянна, можно было бы просто написать результат, как:

c = [a[b[0]]] + [a[b[1]]] + [a[b[2]]] 

Или еще проще, если индексы сами по себе являются константами ...

c = [a[1]] + [a[2]] + [a[5]] 

Или если существует ряд диапазонов индексов ...

c = a[1:3] + [a[5]] 
+0

Спасибо, что напомнили мне, что '[a] + [b] = [a, b]' – onewhaleid

1

Другим решением может быть с помощью панд Серия:

import pandas as pd 

a = pd.Series([-2, 1, 5, 3, 8, 5, 6]) 
b = [1, 2, 5] 
c = a[b] 

Вы можете затем преобразовать C обратно в список, если вы хотите:

c = list(c)