Sage Weasley
Sage Weasley

Reputation: 3

Max in a list and its index in Haskell -- in the case of a tie, I need the element closest to the head

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

Answers (2)

jpmarinier
jpmarinier

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

Mihalis
Mihalis

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

Related Questions