使用 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 语法基本原理的所有建议和解释。

在这个乏味的网站上找到以下内容后,我想我找到了一个我喜欢的解决方案:

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]
318738 次浏览

另一种方式:

>>> [i for i in range(len(a)) if a[i] > 2]
[2, 5]

一般来说,请记住 虽然 find是一个现成的功能,列表理解是一个通用的,因此非常强大的解决方案。没有什么可以阻止您用 Python 编写 find函数,并在以后随意使用它。例如:

>>> 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。

也许另一个问题是,“一旦你得到了这些指数,你打算怎么处理它们?”如果您打算使用它们来创建另一个列表,那么在 Python 中,它们是不必要的中间步骤。如果您希望所有的值都匹配给定的条件,只需使用内置过滤器:

matchingVals = filter(lambda x : x>2, a)

或者写下你自己的理解列表:

matchingVals = [x for x in a if x > 2]

如果你想从列表中删除它们,那么 Python 的方法不一定是从列表中删除它们,而是像创建一个新列表一样写一个列表内涵,然后使用左侧的 listvar[:]返回原位:

a[:] = [x for x in a if x <= 2]

Matlab 提供 find,因为它的以数组为中心的模型通过使用数组索引来选择项。当然,可以是在 Python 中完成这项工作的,但是更为 Python 化的方式是使用迭代器和生成器,@EliBendersky 已经提到过这一点。

  • 在 Python 中,您根本不会为此使用索引,而只是处理值ー [value for value in a if value > 2]。通常,处理索引意味着您没有采用最佳方法。

  • 如果您需要一个类似于 Matlab 的 API,那么您可以使用 麻木不仁,这是一个用于多维数组和 Python 中的数值数学的包,其灵感来自 Matlab。您将使用一个 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])
    

即使这是一个迟到的回答: 我认为这仍然是一个非常好的问题,而且 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]

在我的想象中,最完美的方法是创建一个 list 的子类,并添加 index 函数作为类方法。这样就只需要使用过滤器方法:

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

对我来说,这很有效:

>>> import numpy as np
>>> a = np.array([1, 2, 3, 1, 2, 3])
>>> np.where(a > 2)[0]
[2 5]