[英]Finding the index of elements based on a condition using python list comprehension
當來自 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 語法的基本原理提出的所有建議和解釋。
在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]
在Python中,您根本不會使用索引,而只是處理值 - [value for value in a if value > 2]
。 通常處理索引意味着你沒有以最好的方式做事。
如果你確實需要一個類似於Matlab的API,你可以使用numpy ,一個用於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]
一般來說,請記住, 雖然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。 使用生成器和迭代器會更加Pythonic。
對我來說效果很好:
>>> import numpy as np
>>> a = np.array([1, 2, 3, 1, 2, 3])
>>> np.where(a > 2)[0]
[2 5]
即使這是一個遲到的答案:我認為這仍然是一個非常好的問題,恕我直言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
也許另一個問題是,“一旦你得到它們,你將如何處理這些指數?” 如果您打算使用它們來創建另一個列表,那么在Python中,它們是不必要的中間步驟。 如果您想要所有與給定條件匹配的值,只需使用內置過濾器:
matchingVals = filter(lambda x : x>2, a)
或者編寫自己的列表comprhension:
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已經提到的那樣。
以下應該可以工作(但我手頭沒有 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]
這是一個很好的解決方案。 但是內置類型並不意味着被子類化。 您可以使用組合而不是 inheritance。這應該有效:
import numpy
class my_array:
def __init__(self, data):
self.data = numpy.array(data)
def find(self, b):
r = numpy.array(list(range(len(self.data))))
return list(r[b])
>>> a = my_array([1, 2, 3, 1, 2, 3])
>>> a.find(a.data>2)
[2,5]
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.