Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Indentifying the LAST occurrence of an item in a list

0 views
Skip to first unread message

tkp...@hotmail.com

unread,
Apr 4, 2007, 11:58:49 AM4/4/07
to
For any list x, x.index(item) returns the index of the FIRST
occurrence of the item in x. Is there a simple way to identify the
LAST occurrence of an item in a list? My solution feels complex -
reverse the list, look for the first occurence of the item in the
reversed list, and then subtract its index from the length of the list
- 1, i.e.

LastOcc = len(x) - 1 - x[::-1].index(item)

Is there a simpler solution?

Thanks in advance

Thomas Philips

Terry Reedy

unread,
Apr 4, 2007, 12:55:30 PM4/4/07
to pytho...@python.org

<tkp...@hotmail.com> wrote in message
news:1175702329.3...@w1g2000hsg.googlegroups.com...

Unless I wanted the list reversed, I would simply iterate backwards,
parhaps in a utility function.

def rindex(lis, item):
for i in range(len(lis)-1, -1, -1):
if item == lis[i]:
return i
else:
raise ValueError("rindex(lis, item): item not in lis")

t=[0,1,2,3,0]
print rindex(t,3)
print rindex(t,0)
print rindex(t,4)
# prints 3, 4, and traceback

Terry Jan Reedy

7stud

unread,
Apr 4, 2007, 1:20:50 PM4/4/07
to
On Apr 4, 10:55 am, "Terry Reedy" <tjre...@udel.edu> wrote:
> <tkp...@hotmail.com> wrote in message
>
> news:1175702329.3...@w1g2000hsg.googlegroups.com...
> | For any list x, x.index(item) returns the index of the FIRST
> | occurrence of the item in x. Is there a simple way to identify the
> | LAST occurrence of an item in a list? My solution feels complex -
> | reverse the list, look for the first occurence of the item in the
> | reversed list, and then subtract its index from the length of the list
> | - 1, i.e.
> |
> | LastOcc = len(x) - 1 - x[::-1].index(item)
> |
> | Is there a simpler solution?
>

How about:

l = [1, 2, 1, 3, 1, 5]
target = 1
for index, val in enumerate(l):
if val==1:
lastIndexOf = index

print lastIndexOf

7stud

unread,
Apr 4, 2007, 1:27:28 PM4/4/07
to

Nahh. Horrible solution. You should start at the end of the list.

Terry Reedy

unread,
Apr 4, 2007, 1:34:52 PM4/4/07
to pytho...@python.org

"7stud" <bbxx78...@yahoo.com> wrote in message
news:1175707250.3...@p77g2000hsh.googlegroups.com...

| How about:
|
| l = [1, 2, 1, 3, 1, 5]
| target = 1
| for index, val in enumerate(l):
| if val==1:
| lastIndexOf = index
|
| print lastIndexOf

You might want to initialize lastIndexOf (to None, for instance).
If len(l) = 1000000, you might prefer to start from the end, as I
suggested.

tjr

Tim Williams

unread,
Apr 4, 2007, 1:55:20 PM4/4/07
to tkp...@hotmail.com, pytho...@python.org
On 4 Apr 2007 08:58:49 -0700, tkp...@hotmail.com <tkp...@hotmail.com> wrote:
> For any list x, x.index(item) returns the index of the FIRST
> occurrence of the item in x. Is there a simple way to identify the
> LAST occurrence of an item in a list? My solution feels complex -
> reverse the list, look for the first occurence of the item in the
> reversed list, and then subtract its index from the length of the list
> - 1, i.e.
>
> LastOcc = len(x) - 1 - x[::-1].index(item)
>
> Is there a simpler solution?

Simpler ? That's subjective. :)

You definitely need to search/iterate a reversed list, or start from
the far end of a non-reversed list.

For fun only.

>>> t = [0,1,2,3,0]

>>> def place(t,i):
... for x,y in zip(t,range(len(t)))[::-1]:
... if x == i:
... return y
...
>>> place(t,3)
3
>>> place(t,0)
4

bearoph...@lycos.com

unread,
Apr 4, 2007, 3:39:30 PM4/4/07
to
Terry Reedy:

> def rindex(lis, item):
> for i in range(len(lis)-1, -1, -1):
> if item == lis[i]:
> return i
> else:
> raise ValueError("rindex(lis, item): item not in lis")

This is an alternative, I don't know if it's faster:

def rindex(seq, item):
for pos, el in enumerate(reversed(seq)):
if item == el:
return len(seq) - 1 - pos


else:
raise ValueError("rindex(lis, item): item not in lis")

t = [0, 1, 2, 3, 0]

print rindex(t, 0)
print rindex(t, 3)
print rindex(t, 1)

Bye,
bearophile

John Machin

unread,
Apr 4, 2007, 5:45:22 PM4/4/07
to

If you need to do this for several possible items in the same list, it
may be worthwhile to build a dictionary containing all the answers:

| >>> seq = ['foo', 'bar', 'foo', 'bar', 'zot', 'foo']
| >>> rindex = dict((elt, inx) for inx, elt in enumerate(seq))
| >>> rindex
| {'zot': 4, 'foo': 5, 'bar': 3}

If you tell us what is the higher-level problem, we may be able to
help you further. In other words, if lists did have a rindex method,
what would you be using it to do? Are you constrained to use a list,
or would another data structure be better?

HTH,

John

mkPyVS

unread,
Apr 5, 2007, 2:55:30 PM4/5/07
to
Not sure below is better but it hacks at larger chunks (excuse the 10
second coding)
m = [2,9,1,5,6,3,1,1,9,2]
f = 1
temp = m
location = m.index(f)
gloc = location
temp = m[location:]
while 1:
print(temp)
try:
location = temp.index(f) + 1
gloc += location
except:
break
temp = temp[location:]
#Remove the last 0th element
gloc -= 1
print("Last location = %d" % gloc)

John Machin

unread,
Apr 5, 2007, 8:37:47 PM4/5/07
to
On Apr 6, 4:55 am, "mkPyVS" <mikemine...@hotmail.com> wrote:
> Not sure below is better but it hacks at larger chunks (excuse the 10
> second coding)
> m = [2,9,1,5,6,3,1,1,9,2]
> f = 1
> temp = m

Overwritten 3 statements later

> location = m.index(f)
> gloc = location
> temp = m[location:]
> while 1:
> print(temp)
> try:
> location = temp.index(f) + 1
> gloc += location
> except:
> break
> temp = temp[location:]

Each time you do that you are copying a chunk of the original list.
This could be expensive on a large list. Reminds me of the old joke
about how many marines it takes to paint the barracks: 200 to
oscillate the barracks, one to hold the brush steady. You don't need
to do that. Here's a clue:

| >>> help(list.index)
Help on method_descriptor:

index(...)
L.index(value, [start, [stop]]) -> integer -- return first index
of value

I look forward to your next version.

Cheers,
John

mkPyVS

unread,
Apr 6, 2007, 7:25:42 PM4/6/07
to
On Apr 5, 6:37 pm, "John Machin" <sjmac...@lexicon.net> wrote:
>>> help(list.index)
> Help on method_descriptor:
>
> index(...)
> L.index(value, [start, [stop]]) -> integer -- return first index
> of value
>
> I look forward to your next version.

Great point! I was assuming the temp variable space was static but the
pointer to the start of the list was moving-> shame on me (what
language is this now ;)!

Couldn't resist the temptation to just collect all of the locations as
I traversed

m = [2,9,1,5,6,3,1,1,9,2]
f = 1 #What we're looking for
location = 0 #Start at beginning of list
fIndexs = []
while 1:
try:
location = m.index(f,location) + 1
fIndexs.append(location-1)
except ValueError:
break

print("Last location = %d" % fIndexs[-1])
print("All Items = %s" % fIndexs)

John Machin

unread,
Apr 6, 2007, 8:46:35 PM4/6/07
to
On Apr 7, 9:25 am, "mkPyVS" <mikemine...@hotmail.com> wrote:
> On Apr 5, 6:37 pm, "John Machin" <sjmac...@lexicon.net> wrote:
>
> >>> help(list.index)
> > Help on method_descriptor:
>
> > index(...)
> > L.index(value, [start, [stop]]) -> integer -- return first index
> > of value
>
> > I look forward to your next version.
>
> Great point! I was assuming the temp variable space was static but the
> pointer to the start of the list was moving-> shame on me (what
> language is this now ;)!

Indeed. IMHO every function/method that searches a sequence should
have start/stop arguments so that the caller can search a slice
without actually copying the slice.

>
> Couldn't resist the temptation to just collect all of the locations as
> I traversed
>
> m = [2,9,1,5,6,3,1,1,9,2]
> f = 1 #What we're looking for
> location = 0 #Start at beginning of list
> fIndexs = []
> while 1:
> try:
> location = m.index(f,location) + 1
> fIndexs.append(location-1)
> except ValueError:
> break
>
> print("Last location = %d" % fIndexs[-1])

1. print is a statement, not a function.
2. fIndexs[-1] will crash and burn if there are no occurrences of f in
m.

> print("All Items = %s" % fIndexs)

FWIW, here's my take on a function that emulates the "missing" rindex
method:
8<--- start rindex.py ---
def rindex(seq, value, lo=0, hi=None):
"""If there is an x such that seq[x] == value and lo <= x < hi
return the largest such x, else raise ValueError"""
seqlen = len(seq)
if lo < 0:
lo += seqlen
if lo < 0:
lo = 0
if hi is None:
hi = seqlen
elif hi < 0:
hi += seqlen
if hi < 0:
hi = 0
lo = seq.index(value, lo, hi)
while True:
try:
lo = seq.index(value, lo + 1, hi)
except ValueError:
return lo

if __name__ == "__main__":
import sys
av = sys.argv
print rindex(av[4:], av[1], int(av[2]), int(av[3]))
8<--- end rindex.py ---
Cheers,
John

0 new messages