module Data.Sort ( -- * The Vanilla Sorts L.sort , L.sortBy , L.sortOn -- * Sorting Associations , monoidSortAssocs , monoidSortAssocsBy , groupSortAssocs , groupSortAssocsBy -- * Sorting with Monoids , monoidSort , monoidSortOn , monoidSortBy -- * Unique Sorts , uniqueSort , uniqueSortOn , uniqueSortBy -- * Group Sorting , groupSort , groupSortOn , groupSortBy ) where import qualified Data.List as L import Data.Monoid import Data.Ord -- | Sort the list of associations, aggregating duplicates with the -- monoid. monoidSortAssocs :: (Monoid a,Ord k) => [(k,a)] -> [(k,a)] monoidSortAssocs = monoidSortAssocsBy compare -- | Sort the list of associations, aggregating duplicates with the -- monoid and ordering the keys with the argument compare function. monoidSortAssocsBy :: (Monoid a) => (k->k->Ordering) -> [(k,a)] -> [(k,a)] monoidSortAssocsBy cmp = groupSortAssocsBy cmp $ const monoid_group -- | Sort the list of associations, aggregating duplicates with the -- supplied function. groupSortAssocs :: Ord k => (k->a->[a]->b) -> [(k,a)] -> [(k,b)] groupSortAssocs = groupSortAssocsBy compare -- | Sort the list of associations, aggregating duplicates with the -- supplied function and ordering the keys with the argument -- compare function. groupSortAssocsBy :: (k->k->Ordering) -> (k->a->[a]->b) -> [(k,a)] -> [(k,b)] groupSortAssocsBy cmp0 grp0 = groupSortBy cmp grp where cmp (k,_) (k',_) = cmp0 k k' grp (k,y) ps = (,) k $ grp0 k y $ map snd ps -- | Sort the list, agregating duplicates with the monoid. monoidSort :: (Monoid a,Ord a) => [a] -> [a] monoidSort = monoidSortBy compare -- | Sort the list, agregating duplicates with the monoid and -- ordering the elements by the items generated by the -- argument function. monoidSortOn :: (Monoid a,Ord k) => (a->k) -> [a] -> [a] monoidSortOn chg = groupSortOn chg $ const monoid_group -- | Sort the list, agregating duplicates with the monoid -- and ordering the keys with the argument compare function. monoidSortBy :: Monoid a => (a->a->Ordering) -> [a] -> [a] monoidSortBy cmp = groupSortBy cmp monoid_group -- | Sort the list, discarding duplicates. uniqueSort :: Ord a => [a] -> [a] uniqueSort = uniqueSortBy compare -- | Sort the list, discarding duplicates and -- ordering the elements by the items generated by the -- argument function. uniqueSortOn :: Ord k => (a->k) -> [a] -> [a] uniqueSortOn chg = groupSortOn chg $ const const -- | Sort the list, discarding duplicates and ordering the keys with -- the argument compare function. uniqueSortBy :: (a->a->Ordering) -> [a] -> [a] uniqueSortBy cmp = groupSortBy cmp const -- | Sort a list of elements with a stable sort, grouping together the -- equal elements with the argument grouping function groupSort :: (Ord a) => (a->[a]->b) -> [a] -> [b] groupSort = groupSortBy compare -- | Sort a list of elements with a stable sort, using the argument -- @compare@ function determine the ordering, grouping together the -- equal elements with the grouping function groupSortOn :: Ord k => (a->k) -> (k->a->[a]->b) -> [a] -> [b] groupSortOn chg grp = groupSortBy (comparing fst) grp_val . map inj where grp_val a as = grp k (snd a) $ map snd as where k = fst a inj x = k `seq` (k,x) where k = chg x -- | Sort a list of elements with a stable sort, grouping together the -- equal elements with the argument grouping function. groupSortBy :: (a->a->Ordering) -> (a->[a]->b) -> [a] -> [b] groupSortBy cmp grp = aggregate . L.sortBy cmp where aggregate [] = [] aggregate (h:t) = seq g $ g : aggregate rst where g = grp h eqs (eqs,rst) = span is_le t is_le x = case cmp x h of LT -> True EQ -> True GT -> False -- the monoid_group helper monoid_group :: Monoid a => a -> [a] -> a monoid_group x xs = x <> mconcat xs