Подтвердить что ты не робот

Поиск индекса элементов на основе условия с использованием понимания списка 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]
4b9b3361

Ответ 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]