patternpythonMinor
Find the locally biggest or equal values including corners in an array
Viewed 0 times
theequalarraylocallybiggestincludingfindvaluescorners
Problem
I am looking for a function, that will find in array of n integers highest or equal locally values including corners.
My code is probably wrong, and I somehow think solution is in some library like NumPy or SciPy, but I do not know how to find it:
I have some tests to test it:
And it passes it, but it is probably not the best code and I am probably inventing wheel one more time.
My code is probably wrong, and I somehow think solution is in some library like NumPy or SciPy, but I do not know how to find it:
def look_for_maximas(vals):
'''
actually look for hills, 1, 0, 1, 1, 0, 1, 1, 2, 1, 0, 0 should return indexes 0, 2, 3, 7
:param vals:
:return:
'''
if len(vals) == 0:
return []
res = []
buff = [0]
is_candidate = True
i = 1
while i vals[i-1]:
is_candidate = True
buff = [i]
elif vals[i] == vals[i-1] and is_candidate:
buff.append(i)
else:
if is_candidate:
res += buff
is_candidate = False
buff = []
i += 1
if is_candidate:
res += buff
return resI have some tests to test it:
assert look_for_maximas([1, 0, 1, 1, 0, 1, 1, 2, 1, 0, 0]) == [0, 2, 3, 7]
assert look_for_maximas([0]) == [0]
assert look_for_maximas([0, 1, 0]) == [1]
assert look_for_maximas([]) == []
assert look_for_maximas([0, 0, 0, 0]) == [0, 1, 2, 3]
assert look_for_maximas([i for i in repeat(0, 1000)]) == range(0, 1000)
assert look_for_maximas(
[100, 0, 0, 100, 10, 0, 10, 10, 0, 5, 3, 0, 0, 10, 10, 10, 10, 100, 0, 1]) == [0, 3, 6, 7, 9, 17, 19]And it passes it, but it is probably not the best code and I am probably inventing wheel one more time.
Solution
First off you can change the while loop to a for loop.
This makes the program easier to understand. As then there is no
It is also un-pythonic to do:
Instead do:
As you want it to work with edge cases, what about generators? And other objects that are iterable, but not index-able.
I would change the
And then you can change the for loop to use
now it will work with anything that is iterable. And so it will work with generators.
Both
From the Python time complexity page.
Internally, a list is represented as an array; the largest costs come from growing beyond the current allocation size (because everything must move)
So using
It is not as fast as a NumPy or SciPi solution, but can be a lot faster than using lists.
I tested this by doing
for i in range(1, len(vals)):This makes the program easier to understand. As then there is no
i += 1.It is also un-pythonic to do:
if len(vals) == 0:Instead do:
if not vals:As you want it to work with edge cases, what about generators? And other objects that are iterable, but not index-able.
I would change the
if not vals: to a try except.vals = iter(vals)
try:
prev = next(vals)
except StopIteration:
return []And then you can change the for loop to use
enumerate.for i, curr in enumerate(vals, 1):
if curr > prev:
is_candidate = True
buff = [i]
elif curr == prev and is_candidate:
buff.append(i)
else:
if is_candidate:
res += buff
is_candidate = False
buff = []
prev = currnow it will work with anything that is iterable. And so it will work with generators.
Both
yield and list.append are \$O(1)\$. However I like to think that list.append is \$O(n)\$. This is as lists rely on the amortized worst case to be \$O(1)\$.From the Python time complexity page.
Internally, a list is represented as an array; the largest costs come from growing beyond the current allocation size (because everything must move)
So using
range, assuming you're using Python3, and generators can be better.def look_for_maximas(vals):
def res(vals):
vals = iter(vals)
# Exploiting for-loops and generators. It's kinda surprising this works.
prev = next(vals)
start = 0
# Has to be in scope for the last yield.
i = 1
for curr in vals:
if curr > prev:
start = i
elif curr < prev:
if start is not None:
yield range(start, i)
start = None
prev = curr
i += 1
if start is not None:
yield range(start, i)
for range_ in res(vals):
for i in range_:
yield iIt is not as fast as a NumPy or SciPi solution, but can be a lot faster than using lists.
I tested this by doing
assert list(look_for_maximas(...)) == .... And it worked for them all. However I don't have repeat, and removed that test.Code Snippets
for i in range(1, len(vals)):if len(vals) == 0:if not vals:vals = iter(vals)
try:
prev = next(vals)
except StopIteration:
return []for i, curr in enumerate(vals, 1):
if curr > prev:
is_candidate = True
buff = [i]
elif curr == prev and is_candidate:
buff.append(i)
else:
if is_candidate:
res += buff
is_candidate = False
buff = []
prev = currContext
StackExchange Code Review Q#98574, answer score: 4
Revisions (0)
No revisions yet.