module Axel.Utils.List where
import Axel.Prelude
import Axel.Utils.Tuple
( Annotated
, annotate
, annotateWith
, annotation
, unannotate
)
import Control.Lens ((%~), (&), (^.), _1, _2)
import Data.Function (on)
import Data.List (elemIndex, isPrefixOf, sortOn)
import Data.List.NonEmpty (NonEmpty((:|)))
import qualified Data.List.NonEmpty as NE (groupBy, head, map)
import Data.Maybe (fromJust, listToMaybe)
head' :: [a] -> Maybe a
head' = listToMaybe
-- Alternatively, `unsafeHead = head`.
unsafeHead :: [a] -> a
unsafeHead = fromJust . listToMaybe
groupAllWith :: (Ord b) => (a -> b) -> [a] -> [Annotated b (NonEmpty a)]
groupAllWith f =
map extractAnnotation .
NE.groupBy ((==) `on` (^. annotation)) . map (annotateWith f)
where
extractAnnotation xs =
annotate (NE.head xs ^. annotation) (NE.map unannotate xs)
-- This is not stable in the technical sense of the term, just roughly stable-ish for limited use cases.
stablyGroupAllWith ::
(Eq a, Ord b) => (a -> b) -> [a] -> [Annotated b (NonEmpty a)]
stablyGroupAllWith f xs =
map unannotate $
sortOn (^. annotation) $
map
(annotateWith $ \(groupRepresentative :| _, _) ->
elemIndex groupRepresentative xs) $
groupAllWith f xs
removeOut :: (Eq a) => (a -> Bool) -> [a] -> ([a], [a])
removeOut f xs =
let removed = filter f xs
xs' = filter (not . (`elem` removed)) xs
in (xs', removed)
remove :: (Eq a) => (a -> Bool) -> [a] -> [a]
remove f xs = fst $ removeOut f xs
-- https://stackoverflow.com/a/26530188/2391244
takeUntil :: (Eq a) => [a] -> [a] -> [a]
takeUntil _ [] = []
takeUntil [] _ = []
takeUntil xs (y:ys) =
if xs `isPrefixOf` (y : ys)
then []
else y : takeUntil xs ys
filterMapOut :: (a -> Maybe b) -> [a] -> ([a], [b])
filterMapOut f =
foldr
(\x acc ->
case f x of
Just x' -> acc & _2 %~ (x' :)
Nothing -> acc & _1 %~ (x :))
([], [])
filterMap :: (a -> Maybe b) -> [a] -> [b]
filterMap f xs = snd $ filterMapOut f xs
only :: a -> [a]
only x = [x]