Search for index of elements based on condition using python list comprehension

The following Python code looks very long when coming from a Matlab background

>>> a = [1, 2, 3, 1, 2, 3] >>> [index for index,value in enumerate(a) if value > 2] [2, 5] 

When in Matlab I can write:

 >> a = [1, 2, 3, 1, 2, 3]; >> find(a>2) ans = 3 6 

Is there a short method for writing this in Python, or am I just sticking to a long version?




Thank you for all the suggestions and explanations for the rationale for Python syntax.

After finding the following content on a numpy website, I think I found a solution that I like:

http://docs.scipy.org/doc/numpy/user/basics.indexing.html#boolean-or-mask-index-arrays

Applying the information from this website to my problem above will give you the following:

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

Then the following should work (but I don't have a Python interpreter to test):

 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] 
+57
python
01 Sep '11 at 12:31 on
source share
5 answers
  • In Python, you will not use indexes for this at all, but you are simply dealing with values [value for value in a if value > 2] . Usually handling indexes means you are not doing the best thing.

  • If you need an API similar to Matlab, you would use numpy , a package for multidimensional arrays, and numerical math in Python, which is heavily inspired by Matlab. You would use a numpy array instead of a list.

     >>> 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]) 
+50
Sep 01 '11 at 13:20
source share

Another way:

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

In general, remember that while find is a ready-made function, lists are a general and therefore very powerful solution . Nothing prevents you from writing the find function in Python and using it later, as you wish. I.e:.

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

Please note that I use lists here to mimic Matlab. It would be more Pythonic to use generators and iterators.

+29
Sep 01 '11 at 12:35
source share

Perhaps another question: "What are you going to do with these indicators as soon as you get them?" If you intend to use them to create another list, then in Python they are an unnecessary middle step. If you need all the values ​​that match this condition, just use the built-in filter:

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

Or write your own list:

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

If you want to remove them from the list, the Pythonic path does not have to be removed from the list, but write an understanding of the list as if you were creating a new list and assigning it back to the place using listvar[:] on the left side:

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

Matlab supplies find because its array-oriented model works by fetching elements using their array indices. You can do this in Python, of course, but the more the Pythonic method uses iterators and generators, as @EliBendersky already mentioned.

+5
Sep 01 '11 at 13:16
source share

Even if this is a late answer: I think this is still a very good question, and IMHO Python (without additional libraries or toolkits like numpy) still does not have a convenient method for accessing the indexes of list items according to the filter manually defined.

You can manually define a function that provides this functionality:

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

Output: [0, 4]

In my imagination, the ideal way would be to create a child list class and add an index function as a class method. Thus, only the filtering method is needed:

 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) 

I elaborated on this topic: http://tinyurl.com/jajrr87

+4
Jan 20 '16 at 14:57
source share

For me, this works well:

 >>> import numpy as np >>> a = np.array([1, 2, 3, 1, 2, 3]) >>> np.where(a > 2)[0] [2 5] 
+1
Sep 11 '17 at 0:09 on
source share



All Articles