Indentifying the LAST occurrence of an item in a list

T

tkpmep

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
 
T

Terry Reedy

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

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

7stud

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

7stud

| 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

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

Terry Reedy

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

bearophileHUGS

Terry Reedy:
def rindex(lis, item):
for i in range(len(lis)-1, -1, -1):
if item == lis:
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
 
J

John Machin

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?

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
 
M

mkPyVS

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

John Machin

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
 
M

mkPyVS

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

John Machin

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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,479
Members
44,899
Latest member
RodneyMcAu

Latest Threads

Top