How to find the last occurrence of an item in a Python list

Say I have this list:

li = ["a", "b", "a", "c", "x", "d", "a", "6"]

As far as help showed me, there is not a builtin function that returns the last occurrence of a string (like the reverse of index). So basically, how can I find the last occurrence of "a" in the given list?

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

If you are actually using just single letters like shown in your example, then str.rindex would work handily. This raises a ValueError if there is no such item, the same error class as list.index would raise. Demo:

>>> li = ["a", "b", "a", "c", "x", "d", "a", "6"]
>>> ''.join(li).rindex('a')
6

For the more general case you could use list.index on the reversed list:

>>> len(li) - 1 - li[::-1].index('a')
6

The slicing here creates a copy of the entire list. That’s fine for short lists, but for the case where li is very large, efficiency can be better with a lazy approach:

def list_rindex(li, x):
    for i in reversed(range(len(li))):
        if li[i] == x:
            return i
    raise ValueError("{} is not in list".format(x))

One-liner version:

next(i for i in reversed(range(len(li))) if li[i] == 'a')

Method 2

A one-liner that’s like Ignacio’s except a little simpler/clearer would be

max(loc for loc, val in enumerate(li) if val == 'a')

It seems very clear and Pythonic to me: you’re looking for the highest index that contains a matching value. No nexts, lambdas, reverseds or itertools required.

Method 3

Many of the other solutions require iterating over the entire list. This does not.

def find_last(lst, elm):
  gen = (len(lst) - 1 - i for i, v in enumerate(reversed(lst)) if v == elm)
  return next(gen, None)

Edit: In hindsight this seems like unnecessary wizardry. I’d do something like this instead:

def find_last(lst, sought_elt):
    for r_idx, elt in enumerate(reversed(lst)):
        if elt == sought_elt:
            return len(lst) - 1 - r_idx

Method 4

>>> (x for x in reversed(list(enumerate(li))) if x[1] == 'a').next()[0]
6

>>> len(li) - (x for x in enumerate(li[::-1]) if x[1] == 'a').next()[0] - 1
6

Method 5

I like both wim’s and Ignacio’s answers. However, I think itertools provides a slightly more readable alternative, lambda notwithstanding. (For Python 3; for Python 2, use xrange instead of range).

>>> from itertools import dropwhile
>>> l = list('apples')
>>> l.index('p')
1
>>> next(dropwhile(lambda x: l[x] != 'p', reversed(range(len(l)))))
2

This will raise a StopIteration exception if the item isn’t found; you could catch that and raise a ValueError instead, to make this behave just like index.

Defined as a function, avoiding the lambda shortcut:

def rindex(lst, item):
    def index_ne(x):
        return lst[x] != item
    try:
        return next(dropwhile(index_ne, reversed(range(len(lst)))))
    except StopIteration:
        raise ValueError("rindex(lst, item): item not in list")

It works for non-chars too. Tested:

>>> rindex(['apples', 'oranges', 'bananas', 'apples'], 'apples')
3

Method 6

With dict

You can use the fact that dictionary keys are unique and when building one with tuples only the last assignment of a value for a particular key will be used. As stated in other answers, this is fine for small lists but it creates a dictionary for all unique values and might not be efficient for large lists.

dict(map(reversed, enumerate(li)))["a"]

6

Method 7

I came here hoping to find someone had already done the work of writing the most efficient version of list.rindex, which provided the full interface of list.index (including optional start and stop parameters). I didn’t find that in the answers to this question, or here, or here, or here. So I put this together myself… making use of suggestions from other answers to this and the other questions.

def rindex(seq, value, start=None, stop=None):
  """L.rindex(value, [start, [stop]]) -> integer -- return last index of value.
  Raises ValueError if the value is not present."""
  start, stop, _ = slice(start, stop).indices(len(seq))
  if stop == 0:
    # start = 0
    raise ValueError('{!r} is not in list'.format(value))
  else:
    stop -= 1
    start = None if start == 0 else start - 1
  return stop - seq[stop:start:-1].index(value)

The technique using len(seq) - 1 - next(i for i,v in enumerate(reversed(seq)) if v == value), suggested in several other answers, can be more space-efficient: it needn’t create a reversed copy of the full list. But in my (offhand, casual) testing, it’s about 50% slower.

Method 8

last_occurence=len(yourlist)-yourlist[::-1].index(element)-1

just easy as that.no need to import or create a function.

Method 9

lastIndexOf = lambda array, item: len(array) - (array[::-1].index(item)) - 1

Method 10

Love @alcalde’s solution, but faced ValueError: max() arg is an empty sequence if none of the elements match the condition.

To avoid the error set default=None:

max((loc for loc, val in enumerate(li) if val == 'a'), default=None)

Method 11

Use a simple loop:

def reversed_index(items, value):
    for pos, curr in enumerate(reversed(items)):
        if curr == value:
            return len(items) - pos - 1
    raise ValueError("{0!r} is not in list".format(value))

Method 12

If the list is small, you can compute all indices and return the largest:

index = max(i for i, x in enumerate(elements) if x == 'foo')

Method 13

Here is a function for finding the last occurrence of an element in a list. A list and an element are passed to the function.

li = ["a", "b", "a", "c", "x", "d", "a", "6"]
element = "a"

def last_occurrence(li,element):
    for i in range(len(li)-1,0,-1):
        if li[i] == element:
            return i

    return -1

last_occ = last_occurrence(li, element)
if (last_occ != -1):
    print("The last occurrence at index : ",last_occ)
else:
    print("Element not found")

Inside the last_occurrence function a for loop is used with range. which will iterate the list in reverse order. if the element of the current index match the searched element, the function will return the index.
In case after comparing all elements in the list the searched element is not found function will return -1.

Method 14

def rindex(lst, val):
    try:
        return next(len(lst)-i for i, e in enumerate(reversed(lst), start=1) if e == val)
    except StopIteration:
        raise ValueError('{} is not in list'.format(val))

Method 15

val = [1,2,2,2,2,2,4,5].

If you need to find last occurence of 2

last_occurence = (len(val) -1) - list(reversed(val)).index(2)

Method 16

Here’s a little one-liner for obtaining the last index, using enumerate and a list comprehension:

li = ["a", "b", "a", "c", "x", "d", "a", "6"]
[l[0] for l in enumerate(li) if l[1] == "a"][-1]


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x