Поиск индекса элементов на основе условия с использованием понимания списка python
Следующий код Python выглядит очень длинным, когда приходит из фона Matlab
>>> a = [1, 2, 3, 1, 2, 3]
>>> [index for index,value in enumerate(a) if value > 2]
[2, 5]
Когда в Matlab я могу написать:
>> a = [1, 2, 3, 1, 2, 3];
>> find(a>2)
ans =
3 6
Есть ли короткий метод написания этого в Python, или я просто придерживаюсь длинной версии?
Благодарим вас за все предложения и объяснения обоснования синтаксиса Python.
После нахождения на веб-сайте numpy следующего содержания, я думаю, что нашел решение, которое мне нравится:
http://docs.scipy.org/doc/numpy/user/basics.indexing.html#boolean-or-mask-index-arrays
Применяя информацию с этого веб-сайта к моей проблеме выше, вы получите следующее:
>>> from numpy import array
>>> a = array([1, 2, 3, 1, 2, 3])
>>> b = a>2
array([False, False, True, False, False, True], dtype=bool)
>>> r = array(range(len(b)))
>>> r(b)
[2, 5]
Затем должно работать следующее (но у меня нет интерпретатора Python для проверки):
class my_array(numpy.array):
def find(self, b):
r = array(range(len(b)))
return r(b)
>>> a = my_array([1, 2, 3, 1, 2, 3])
>>> a.find(a>2)
[2, 5]
Ответы
Ответ 1
-
В Python вы не будете использовать индексы для этого вообще, но просто имеете дело с значениями [value for value in a if value > 2]
. Обычно обращение с индексами означает, что вы не делаете что-то наилучшим образом.
-
Если вам нужен API, похожий на Matlab, вы бы использовали numpy, пакет для многомерных массивов и числовую математику в Python, которая сильно вдохновленный Матлабом. Вы бы использовали массив numpy вместо списка.
>>> import numpy
>>> a = numpy.array([1, 2, 3, 1, 2, 3])
>>> a
array([1, 2, 3, 1, 2, 3])
>>> numpy.where(a > 2)
(array([2, 5]),)
>>> a > 2
array([False, False, True, False, False, True], dtype=bool)
>>> a[numpy.where(a > 2)]
array([3, 3])
>>> a[a > 2]
array([3, 3])
Ответ 2
Другой способ:
>>> [i for i in range(len(a)) if a[i] > 2]
[2, 5]
В общем, помните, что , тогда как find
- готовая функция, списки - это общее и, следовательно, очень мощное решение. Ничто не мешает вам писать функцию find
в Python и использовать ее позже, как вы пожелаете. То есть:.
>>> def find_indices(lst, condition):
... return [i for i, elem in enumerate(lst) if condition(elem)]
...
>>> find_indices(a, lambda e: e > 2)
[2, 5]
Обратите внимание, что я использую списки здесь, чтобы имитировать Matlab. Было бы более Pythonic использовать генераторы и итераторы.
Ответ 3
Возможно, еще один вопрос: "Что вы собираетесь делать с этими показателями, как только вы их получите?" Если вы собираетесь использовать их для создания другого списка, то в Python они являются ненужным средним шагом. Если вам нужны все значения, соответствующие данному условию, просто используйте встроенный фильтр:
matchingVals = filter(lambda x : x>2, a)
Или напишите свой собственный список:
matchingVals = [x for x in a if x > 2]
Если вы хотите удалить их из списка, то путь Pythonic не обязательно должен удаляться из списка, но пишите понимание списка, как если бы вы создавали новый список, и назначая обратно на место с помощью listvar[:]
в левой части:
a[:] = [x for x in a if x <= 2]
Matlab поставляет find
, потому что его массив-ориентированная модель работает, выбирая элементы, используя их индексы массива. Вы можете сделать это на Python, конечно, но чем больше Pythonic-метод использует итераторы и генераторы, как уже упоминалось @EliBendersky.
Ответ 4
Даже если это поздний ответ: я думаю, что это по-прежнему очень хороший вопрос, и IMHO Python (без дополнительных библиотек или наборов инструментов, таких как numpy) по-прежнему не имеет удобного метода для доступа к индексам элементов списка в соответствии с фильтром, определенным вручную.
Вы можете вручную определить функцию, которая обеспечивает эту функциональность:
def indices(list, filtr=lambda x: bool(x)):
return [i for i,x in enumerate(list) if filtr(x)]
print(indices([1,0,3,5,1], lambda x: x==1))
Выход: [0, 4]
В моем воображении идеальным способом будет создание дочернего класса списка и добавление функции индексов в качестве метода класса. Таким образом, необходим только метод фильтрации:
class MyList(list):
def __init__(self, *args):
list.__init__(self, *args)
def indices(self, filtr=lambda x: bool(x)):
return [i for i,x in enumerate(self) if filtr(x)]
my_list = MyList([1,0,3,5,1])
my_list.indices(lambda x: x==1)
Я подробно остановился на этой теме:
http://tinyurl.com/jajrr87
Ответ 5
Для меня это хорошо работает:
>>> import numpy as np
>>> a = np.array([1, 2, 3, 1, 2, 3])
>>> np.where(a > 2)[0]
[2 5]