module Data.List.FastNub where
import Data.List
import Data.Function
type FastNub a = (Eq a, Ord a)
fastNub :: FastNub a => [a] -> [a]
fastNub = map head . group . sort
fastNubBy :: (a->a->Ordering) -> [a] -> [a]
fastNubBy _ [] = []
fastNubBy _ [e] = [e]
fastNubBy cmp es = merge(fastNubBy cmp lhs)(fastNubBy cmp rhs)
where (lhs,rhs) = splitAt (length es `quot` 2) es
merge [] rs = rs
merge ls [] = ls
merge (l:ls) (r:rs) = case cmp l r of
LT -> l : merge ls (r:rs)
GT -> r : merge (l:ls) rs
EQ -> merge (l:ls) rs
fastNubByWith :: (a->a->Ordering) -> (a->a->a) -> [a] -> [a]
fastNubByWith _ _ [] = []
fastNubByWith _ _ [e] = [e]
fastNubByWith cmp cmb es = merge(fastNubByWith cmp cmb lhs)(fastNubByWith cmp cmb rhs)
where (lhs,rhs) = splitAt (length es `quot` 2) es
merge [] rs = rs
merge ls [] = ls
merge (l:ls) (r:rs) = case cmp l r of
LT -> l : merge ls (r:rs)
GT -> r : merge (l:ls) rs
EQ -> merge (cmb l r : ls) rs
sfGroupBy :: (a->a->Ordering) -> [a] -> [[a]]
sfGroupBy cmp = fastNubByWith (cmp`on`head) (++) . map(:[])