By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
434,572 Members | 963 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 434,572 IT Pros & Developers. It's quick & easy.

Indentifying the LAST occurrence of an item in a list

P: n/a
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

Apr 4 '07 #1
Share this Question
Share on Google+
10 Replies


P: n/a

<tk****@hotmail.comwrote in message
news:11**********************@w1g2000hsg.googlegro ups.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?

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

Apr 4 '07 #2

P: n/a
On Apr 4, 10:55 am, "Terry Reedy" <tjre...@udel.eduwrote:
<tkp...@hotmail.comwrote in message

news:11**********************@w1g2000hsg.googlegro ups.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

Apr 4 '07 #3

P: n/a
On Apr 4, 11:20 am, "7stud" <bbxx789_0...@yahoo.comwrote:
On Apr 4, 10:55 am, "Terry Reedy" <tjre...@udel.eduwrote:
<tkp...@hotmail.comwrote in message
news:11**********************@w1g2000hsg.googlegro ups.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
Nahh. Horrible solution. You should start at the end of the list.

Apr 4 '07 #4

P: n/a

"7stud" <bb**********@yahoo.comwrote in message
news:11**********************@p77g2000hsh.googlegr oups.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

Apr 4 '07 #5

P: n/a
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

Apr 4 '07 #6

P: n/a
On Apr 5, 1:58 am, 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?
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

Apr 4 '07 #7

P: n/a
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)

Apr 5 '07 #8

P: n/a
On Apr 6, 4:55 am, "mkPyVS" <mikemine...@hotmail.comwrote:
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

Apr 6 '07 #9

P: n/a
On Apr 5, 6:37 pm, "John Machin" <sjmac...@lexicon.netwrote:
>>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)

Apr 6 '07 #10

P: n/a
On Apr 7, 9:25 am, "mkPyVS" <mikemine...@hotmail.comwrote:
On Apr 5, 6:37 pm, "John Machin" <sjmac...@lexicon.netwrote:
>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

Apr 7 '07 #11

This discussion thread is closed

Replies have been disabled for this discussion.