使用Python列表理解基于条件查找元素的索引

来自Matlab背景的下面的Python代码看起来很长

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

在numpy网站上find以下内容后,我想我find了一个我喜欢的解决scheme:

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解释器来testing它):

 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] 
  • 在Python中,你根本就不会使用索引,而只是处理值 – [value for value in a if value > 2] 。 通常处理索引意味着你没有做最好的方法。

  • 如果你确实需要一个类似于Matlab的API,你可以使用numpy ,一个用于multidimensional array和数值math的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]) 

其他方式:

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

一般来说,请记住, 尽pipefind是一个现成的函数,但列表推导是一个普遍的,因此也是非常强大的解决scheme 。 没有什么能阻止你在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。 使用生成器和迭代器会更加Pythonic。

也许另外一个问题是,“一旦你拿到这些指数,你会怎么做? 如果你打算使用它们来创build另一个列表,那么在Python中,它们是不必要的中间步骤。 如果你想要所有符合给定条件的值,只需使用内置filter:

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

或者编写你自己的列表compransion:

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

如果你想从列表中删除它们,那么Pythonic的方式不一定是从列表中删除,而是写一个列表理解,就好像你正在创build一个新的列表,并使用listvar[:]就地分配左手边:

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

Matlab提供的find是因为其以数组为中心的模型通过使用数组索引来select项目。 当然,你可以用Python做到这一点,但Pythonic的方法是使用迭代器和生成器,正如@EliBendersky所提到的。

即使这是一个迟到的答案:我认为这仍然是一个很好的问题,恕我直言,Python(没有额外的库或工具包如numpy)仍然缺乏一个方便的方法来访问列表元素根据手动定义的filter指数。

你可以手动定义一个函数,它提供了这个function:

 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]

在我的想象中,完美的方法是创build一个子类的列表,并添加索引函数作为类的方法。 用这种方法只需要过滤方法:

 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]