Is there any way to find out local maxima of a list using foldr
or foldl
or maybe I have to use unfoldr
because of first and last elements of list aren't local maximums?
I understand how to find it using recursion with guards, e.g.
localMax :: [Int] -> [Int]
localMax [] = []
localMax (x:[]) = []
localMax (x:y:[]) = []
localMax (x:y:z:zs)
| y > z && y > x = y:localMax (y:z:zs)
| otherwise = localMax (y:z:zs)
I'll try to only use the fold, as you asked. What about something like this?
lmax (x:y:xs) = third $ foldl f (x,y,[]) xs
where
third (_, _, x) = x
f (x, y, ls) z = (y, z, if y > x && y > z then y:ls else ls)
The idea is that you pass a tuple in the fold instead of a list of results. The tuple (a triple) will contain the last two elements and the list of results. The function evaluates whether the second element of the triple is a local minimum w.r.t. the first element (its predecessor) and the current element passed by the fold (its successor).
ghci> lmax [1,3,2]
[3]
ghci> lmax [3,4,2,5,1,7,6,1,9]
[7,5,4]
ghci> lmax [1..10]
[]
ghci> lmax []
*** Exception: test.hs:(4,1)-(5,66): Non-exhaustive patterns in function lmax
Anyway, from this it should be easy to use whatever method you prefer in order to return an empty result list when the input list is too short.
Please note that, by using foldl
, every new result is appended at the top. Because of this, the list of results is reversed. You might want to reverse again lmax
's results if you want to have them in the same order as in the original list: lmax' = reverse . lmax
.