Reputation: 3
My code as below
(value, index) = maximumBy (comparing fst) (zip list [0..])
works fine in most cases, however, in case of a tie, it returns the index that is closest to the tail, which is the opposite of what I want.
Namely, if the list is xs = [2,7,3,7]
, I want it to return (7,1)
instead of (7,3)
. Is there an easy way to do it, or I need to rewrite it completely?
Upvotes: 0
Views: 333
Reputation: 4733
Is there an easy way to do it, or do I need to rewrite it completely ?
If you insist on reusing the library maximumBy
function, you can do it this way: replace the fst
argument to comparing
by something more appropriate.
For example, negate the indices to have the comparison result go the opposite way.
λ>
λ> xs = [2,7,3,7]
λ>
λ> maximumBy (comparing (\(v,x) -> (v,-x))) (zip xs [0..])
(7,1)
λ>
If you are familiar with the Haskell Arrow facility, the same idea can be expressed in more concise fashion:
λ>
λ> import Control.Arrow
λ>
λ> maximumBy (comparing (second id)) (zip xs [0..])
(7,3)
λ>
λ> maximumBy (comparing (second negate)) (zip xs [0..])
(7,1)
λ>
λ> maximumBy (comparing (id *** negate)) (zip xs [0..])
(7,1)
λ>
Upvotes: 1
Reputation: 356
This is the source code for maximumBy
maximumBy :: Foldable t => (a -> a -> Ordering) -> t a -> a
maximumBy cmp = foldl1 max'
where max' x y = case cmp x y of
GT -> x
_ -> y
So by definition it returns the rightmost max element.
The most straightforward way to get the leftmost max element, I suppose, would be to define your own maximumBy'
like so
maximumBy' cmp = fold1 max'
where max' x y = case cmp x y of
LT -> y
_ -> x
All other ways redefine max
in some way, much like how we did here.
That would give you:
> maximumBy' (comparing fst) (zip xs [0..])
> (7,1)
Upvotes: 0