46

I have a list like this:

myList = [0.0, 0.0, 0.0, 2.0, 2.0]

I would like to find the location of the first number in the list that is not equal to zero.

myList.index(2.0)

It works in this example, but sometimes the first nonzero number will be 1 or 3.

Is there a fast way of doing this?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
user2333196
  • 5,406
  • 7
  • 31
  • 35
  • 1
    just be cautious about comparison with floating point numbers – Ant Oct 21 '13 at 18:57
  • 5
    I suspect you're getting a lot of down votes because your question does not demonstrate that you've met the ["what have you tried?"](http://mattgemmell.com/2008/12/08/what-have-you-tried/) requirement. Just a helpful tip for future questions. And also a helpful tip for down-voters, let the user know why you're down voting so that they can make corrections. – Bi Rico Oct 21 '13 at 19:04
  • Related: [What is the best way to get the first item from an iterable matching a condition?](http://stackoverflow.com/questions/2361426/what-is-the-best-way-to-get-the-first-item-from-an-iterable-matching-a-condition), [find first list item that matches criteria](http://stackoverflow.com/questions/9868653/find-first-list-item-that-matches-criteria) – user2314737 May 05 '17 at 09:16

9 Answers9

62

Use next with enumerate:

>>> myList = [0.0 , 0.0, 0.0, 2.0, 2.0]
>>> next((i for i, x in enumerate(myList) if x), None) # x!= 0 for strict match
3
Ashwini Chaudhary
  • 244,495
  • 58
  • 464
  • 504
  • What would be the equivalent for numpy arrays ? – Charly Empereur-mot Dec 15 '20 at 18:58
  • It begs questions about comparison of floating numbers. E.g., what would happen if `42.8/21.4` was used instead of `2.0`? Can you [address](https://stackoverflow.com/posts/19502403/edit) comparison of floating numbers in your answer (even if it is somehow automatically handled (rounding, etc.))? (But ***without*** "Edit:", "Update:", or similar - the answer should appear as if it was written today. And ***without*** reference to this comment.) – Peter Mortensen Feb 04 '22 at 12:58
21

Use filter

Python 2:

myList = [0.0, 0.0, 0.0, 2.0, 2.0]
myList2 = [0.0, 0.0]

myList.index(filter(lambda x: x!=0, myList)[0])       # 3
myList2.index(filter(lambda x: x!=0, myList2)[0])     # IndexError

Python 3: (Thanks for Matthias's comment):

myList.index(next(filter(lambda x: x!=0, myList)))    # 3
myList2.index(next(filter(lambda x: x!=0, myList2)))  # StopIteration
# from Ashwini Chaudhary's answer
next((i for i, x in enumerate(myList) if x), None)    # 3
next((i for i, x in enumerate(myList2) if x), None)   # None

You have to handle special case.

Puffin GDI
  • 1,702
  • 5
  • 27
  • 37
  • 2
    Great alternative too, main difference from `next` is that `next` provides a default value whereas this would raise an exception. – Wtower Mar 30 '15 at 12:18
  • 3
    for python 3 you can use `myList.index(next(filter(lambda x: x!=0, myList)))` – Matthias Sep 29 '16 at 13:48
  • 1
    I like this answer best, but with the Matthias mod to use "next". Note that in either case, depending on the situation you should consider a test of any(myList) first, to make sure there is at least one nonzero value. It may help with program flow and avoiding exceptions. – Starman Apr 09 '19 at 21:01
11

You can use numpy.nonzero:

myList = [0.0, 0.0, 0.0, 2.0, 2.0]
I = np.nonzero(myList)
# The first index is necessary because the vector is within a tuple
first_non_zero_index = I[0][0]
# 3
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
6

Here's a one liner to do it:

val = next((index for index,value in enumerate(myList) if value != 0), None)

Basically, it uses next() to find the first value, or return None if there isn't one. enumerate() is used to make an iterator that iterates over index,value tuples so that we know the index that we're at.

Murph
  • 1,479
  • 2
  • 13
  • 26
5

Use this:

[i for i, x in enumerate(myList) if x][0]
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
SebMa
  • 4,037
  • 29
  • 39
3

Using next with enumerate is excellent when the array is large. For smaller arrays, I would use argmax from NumPy so that you won't need a loop:

import numpy as np

myList = [0.0, 0.0, 0.0, 2.0, 2.0]
myArray = np.array(myList)
np.argmax(myArray > 0)
3
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
cjeiler
  • 55
  • 1
  • 5
  • 3
    This will not find the first nonzero element, e.g. for `[0, 0, 1, 2]`. – cheersmate Oct 08 '18 at 13:39
  • Yes it will, but it's not very intuitive. All elements in `myArray > 0` are either `False` or `True`, so the maximum of that array is `True`. According to the [documentation](https://numpy.org/doc/stable/reference/generated/numpy.argmax.html) for numpy.argmax, "In case of multiple occurrences of the maximum values, the indices corresponding to the first occurrence are returned." So with your example, if `myArray` is `[0, 0, 1, 2]`, then `myArray > 0` is `[False, False, True, True]` and the `argmax` of that is 2. – PieterNuyts Feb 13 '23 at 14:23
1

What about using enumerate? Check the enumerate documentation.

def first_non_zero(mylist):
  for index, number in enumerate(mylist):
    if number != 0: # or 'if number:'
      return index
David Schumann
  • 13,380
  • 9
  • 75
  • 96
Eduardo
  • 4,282
  • 2
  • 49
  • 63
1

Do the following:

print (np.nonzero(np.array(myList))[0][0])

This is more convenient, because along with finding nonzero values, this can also help to apply logic function directly. For example:

print (np.nonzero(np.array(myList)>1))
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
devil in the detail
  • 2,905
  • 17
  • 15
  • Perhaps elaborate a little bit in your answer how floating point comparisons are handled? Presumably it is not *exact* comparison. (But ***without*** "Edit:", "Update:", or similar - the answer should appear as if it was written today.) – Peter Mortensen Feb 04 '22 at 13:15
0

Simply use a list comprehension:

myDict = {x: index for index, x in enumerate(myList) if x}

The indices of the nonzero elements are myDict[element].

Rushy Panchal
  • 16,979
  • 16
  • 61
  • 94