使用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]