{-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE Safe #-} module List ( ordNub , sortOn , uncons , snoc , windows , chunksOf ) where import Data.Bool (otherwise) import Data.Function ((.)) import Data.Int (Int) import Data.List (drop, length, sortBy, take, (++)) import Data.Maybe (Maybe (..)) import Data.Ord (Ord (..), comparing) import qualified Data.Set as Set sortOn :: (Ord o) => (a -> o) -> [a] -> [a] sortOn = sortBy . comparing -- | Fast @nub@ if the contents of the list are orderable -- -- O(n * log n) ordNub :: (Ord a) => [a] -> [a] ordNub l = go Set.empty l where go _ [] = [] go s (x:xs) = if x `Set.member` s then go s xs else x : go (Set.insert x s) xs -- | Deconstruct a list into its first element the rest of the list -- This will evaluate to @Nothing@ if the list is empty. uncons :: [a] -> Maybe (a, [a]) uncons [] = Nothing uncons (x:xs) = Just (x, xs) -- | @(:)@, appending instead of prepending -- @(:)@ is sometimes called cons, so when we append instead of prepend, we call the function @snoc@ -- Note that this has an O(length list) time complexity snoc :: [a] -> a -> [a] snoc as a = as ++ [a] -- | Find all @i@-sized windows in a list windows :: Int -> [a] -> [[a]] windows _ [] = [] windows i xss@(_:xs) | length xss >= i = (take i xss) : windows i xs | otherwise = [] -- | Takes chunks of a given size, the last chunk may be smaller but not empty. chunksOf :: Int -> [a] -> [[a]] chunksOf _ [] = [] chunksOf i xs | length xs >= i = take i xs : chunksOf i (drop i xs) | otherwise = [xs]