In O(n) you can build a dict
that holds all positions of any element of your list:
a = [0,2,0,0,1,0,0,2,0]
pos = {}
for idx, elem in enumerate(a):
pos.setdefault(elem,set())
pos[elem].add(idx)
print(pos) # {0: {0, 2, 3, 5, 6, 8}, 2: {1, 7}, 1: {4}}
Finding the position of one element is just one O(1) operation away:
print(pos[2]) # {1,7}
If you want the first and last occurence, you can do:
print(min(pos[0]),max(pos[0]) # 0 8
You can query other things as well:
# get index of first 2 that is before the 1st 1
print( min(x for x in pos[2] if x < min(pos[1]))) # 1
# get index of all 0s that are after the 1st 1
print( list(x for x in pos[0] if x > min(pos[1]))) # [5, 6, 8]
As for the 2 before 1st 1 and after 1st 1:
firstOneIdx = min(pos[1]) # calc min index of 1 before, so it is not recalc'ed
print( "2 before 1st 1:" , list(x for x in pos[2] if x < firstOneIdx))
print( "2 after 1st 1:" , list(x for x in pos[2] if x > firstOneIdx))
which outputs:
2 before 1st 1: [1]
2 after 1st 1: [7]
You can use min/max
to reduce the lists to 1 element.