1

what could be a nice one-liner to get the highest index in a python array whose value is defined (i.e. not None):

f( [None, 1, 5, None, 3, None, None] )

would return:4 (as the "last" defined element is 4. (with value 3))

Sure a search loop would make the job, but it feels non optimal...

3
  • @FranciscoCouzo that's the value, not the index Commented Oct 20, 2016 at 21:21
  • Fransico 1) that would return the max of the values, which is not the question, (but it can easily be changed to return the index) but more to the point it does use a loop!. Maybe there is no better way... Commented Oct 20, 2016 at 21:23
  • Sorry, I misread the question, I deleted the comment already. Commented Oct 20, 2016 at 21:25

6 Answers 6

3
lst = [None, 1, 5, None, 3, None, None]

# Nothing will be printed if all elements are None.
print max(i for i,num in enumerate(lst) if num is not None)
Sign up to request clarification or add additional context in comments.

3 Comments

No need for max. The last index is the biggest one. [i for i,element in enumerate(l) if element is not None][-1]
Yes. That looks more efficient.
I'd say this answer is "Pythonic enough" and the easiest one to understand.
2

Loop over the reversed of the list and return the first valid item's index:

In [70]: next((len(l) - i for i, j in enumerate(l[::-1], 1) if j is not None), 'NOT FOUND')
Out[70]: 4

Note that since you are looping over the reversed array the correct index would be len(l) - i (if we consider the first index as 1).

If you are looking for a functional and/or more optimized approach you can use numpy and it's where function:

In [1]: import numpy as np

In [2]: lst = [None, 1, 5, None, 3, None, None]

In [4]: np.where(lst)[0][-1]
Out[4]: 4

5 Comments

What if j is 0? You need to be explicit: if j is not None
@Kasramvd I guess that is the best answer, though I expected python to have way to do that without looping. Thx for your answers
@user1159290 how could you possibly do it without looping? You could do it without explicitly writing a loop yourself, e.g. using itertools.dropwhile, but there's still a loop in there!
@jonrsharpe This is what I meant: using some python function ( or a combination of them) not involving visible python looping: such as max() for returning the max value: Of course these functions do loop under the hood, but it is not visible at python level. I thought I was missing something. Maybe not, but many answer where actually intersting!
@user1159290 Checkout the update for a functional approach.
2

A relatively Pythonic solution which does not use indices:

a = [None, 1, 5, None, 3, None, None]
index = next(i for i, j in reversed(tuple(enumerate(a))) if j)

The tuple bugs me, but it is needed as reversed cannot take in a generator.

Comments

2

Another alternative using filter().

>>> my_list = [None, 1, 5, None, 3, None, None]
>>> filter(lambda x: x[1] is not None, enumerate(my_list))[-1][0]
4

But this won't work for empty list or list with all None. But in order to handle that, we can use and and or statements (since you need one line solution):

>>> (filter(lambda x: x is not None, my_list) and filter(lambda x: x[1] is not None, enumerate(my_list))[-1][0]) or -1
4

This expression will return -1 for the above mentioned edge cases.

Comments

1

You could create a generator that iterates on the indices of the list in reverse and tests until a not None value object is reached:

def f(lst):
    try:
        return next(i for i in range(len(lst)-1, 0, -1) if lst[i] is not None)
    except StopIteration:
        print 'no item was found'
        raise

Comments

0

If the input list is very large, you can use itertools and the built-in reversed to avoid iterating or copying the whole thing:

from itertools import dropwhile

def last_non_none(seq):
    return next(dropwhile(lambda x: x is None, reversed(seq)))

This will throw StopIteration if there are no non-None values, which I would argue is more pythonic than returning a default.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.