If you are looking for a functional example, you can probably do (in Ruby)
def derivative_signs(list) (0..list.length-2).map { |i| (list[i+1] - list[i]) <=> 0 }
Based on the calculus, minima / maxima are when the first derivative changes signs. Thus, you can look at derivative_signs(arr) and find all sign changes.
first_derivative_signs = derivative_signs(arr)
Alternatively you can also do
second_derivative = derivative(derivative_signs(arr))
In the list that you indicated, you will receive:
[0, 0, 0, -2, 0, 2, 0, 0, -2, 0, 0, 2]
It is clear that values with the second derivative -2 are highs, and values with the second derivative 2 are lows. The index of the second derivative is the index of the original list + 1. Thus, second_derivative[4] , that is, -2 , corresponds to arr[5] (7), which is the maximum.
Why do we make a “normal” derivative a second time, instead of the derivative_sign?
This is because when a value is repeated twice in a row, you get unwanted behavior.
For example, consider
[1, 3, 6, 6, 7, 5, 4, 6, 9, 10, 8, 7, 5, 10] # first_derivative_signs => [1, 1, 0, 1, -1, -1, 1, 1, 1, -1, -1, -1, 1] # second_derivative_signs => [0, -1, 1, -1, 0, 1, 0, 0, -1, 0, 0, 1] # second_derivative => [0, -1, 1, -2, 0, 2, 0, 0, -2, 0, 0, 2]
Note that second_derivative_signs gives us some “false” minima / maxima, and second_derivative when we check only -2 and 2 is fine.