How to group similar items in a list using Haskell?

Whenever possible, reuse library code.

import Data.Map
sortAndGroup assocs = fromListWith (++) [(k, [v]) | (k, v) <- assocs]

Try it out in ghci:

*Main> sortAndGroup [(1,"aa"),(1,"cc"),(2,"aa"),(3,"ff"),(3,"gg"),(1,"bb")]
fromList [(1,["bb","cc","aa"]),(2,["aa"]),(3,["gg","ff"])]

EDIT In the comments, some folks are worried about whether (++) or flip (++) is the right choice. The documentation doesn’t say which way things get associated; you can find out by experimenting, or you can sidestep the whole issue using difference lists:

sortAndGroup assocs = ($[]) <$> fromListWith (.) [(k, (v:)) | (k, v) <- assocs]
-- OR
sortAndGroup = fmap ($[]) . M.fromListWith (.) . map (fmap (:))

These alternatives are about the same length as the original, but they’re a bit less readable to me.

Leave a Comment