Search code examples
arrayshaskellindexingmax

Haskell: the index of a maximum element in an Array


Given an Array, I need to compute the index of the maximum element (which is assumed to be unique).

My current attempt is:


maxIndex' :: (Ix i, Ord a) => Array i a -> [i] -> i -> a -> i -> a -> i
maxIndex' arr ids index element maxIndex maxElement
  | length ids == 1 && element > maxElement = index
  | length ids == 1 && element <= maxElement = maxIndex
  | element > maxElement = maxIndex' arr (tail ids) (head ids) (arr ! head ids) index element
  | otherwise = maxIndex' arr (tail ids) (head ids) (arr ! head ids) maxIndex maxElement

maxIndex :: (Ix i, Ord a) => Array i a -> i
maxIndex arr = maxIndex' arr (tail (indices arr)) firstIndex firstMaximum firstIndex firstMaximum
  where
    firstIndex = head (indices arr)
    firstMaximum = arr ! firstIndex

The current implementation, however, is incorrect:

print (maxIndex (array (False,True) [(False,54),(True,104)])) -- Prints False.
print (maxIndex (array (False,True) [(True,104),(False,54)])) -- Prints False.

So, what am I missing?


Solution

  • Your maxIndex function is very complicated, and honestly I don't understand what you are doing. In general, If you are doing a lot of head, tail and explicit recursion something has gone already wrong. The easiest approach is to transform the array in a linked list of pairs (index, element), compare them by the second element of the pair, and get the first one (the index)

    import Data.Array
    import Data.Function (on)
    import Data.List (maximumBy)
    
    -- Notice maximumBy is partial
    maxIndex = fst . maximumBy (compare `on` snd) . assocs 
    --         |     |                              |- the list of (index, array_element)
    --         |     |- maximum using a custom comparision function. In this case, compare on second element in the tuple
    --         |- get the first element of the tuple
    main = do  
      let arr = array (False,True) [(False,54),(True,104)]
      print $ maxIndex arr