LastOcc = len(x) - 1 - x[::-1].index(item)
Is there a simpler solution?
Thanks in advance
Thomas Philips
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
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.
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
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
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
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
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
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)
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