module Data.List.Util where
import Data.Bifunctor
import Data.Ext
import qualified Data.Foldable as F
import qualified Data.List as List
import Data.List.NonEmpty (NonEmpty(..))
import qualified Data.List.NonEmpty as NonEmpty
import Data.List.Zipper (allNonEmptyNexts, extractNext)
import qualified Data.List.Zipper as Zipper
import Data.Maybe
import Data.Ord (comparing)
leaveOutOne :: [a] -> [(a,[a])]
leaveOutOne xs = (second F.toList . fromJust . extractNext)
<$> allNonEmptyNexts (Zipper.fromList xs)
minimum1 :: Ord a => [a] -> Maybe a
minimum1 = minimum1By compare
maximum1 :: Ord a => [a] -> Maybe a
maximum1 = minimum1By (flip compare)
minimum1By :: (a -> a -> Ordering) -> [a] -> Maybe a
minimum1By cmp = \case
[] -> Nothing
xs -> Just $ List.minimumBy cmp xs
minimaOn :: Ord b => (a -> b) -> [a] -> [a]
minimaOn f = minimaBy (comparing f)
minimaBy :: (a -> a -> Ordering) -> [a] -> [a]
minimaBy cmp = \case
[] -> []
(x:xs) -> NonEmpty.toList $ List.foldl' (\mins@(m:|_) y -> case m `cmp` y of
LT -> mins
EQ -> (y NonEmpty.<| mins)
GT -> (y:|[])
) (x:|[]) xs
extractMinimaBy :: (a -> a -> Ordering) -> [a] -> [a] :+ [a]
extractMinimaBy cmp = \case
[] -> [] :+ []
(x:xs) -> first NonEmpty.toList $ foldr (\y (mins@(m:|_) :+ rest) ->
case m `cmp` y of
LT -> mins :+ y:rest
EQ -> (y NonEmpty.<| mins) :+ rest
GT -> (y:|[]) :+ NonEmpty.toList mins <> rest
) ((x:|[]) :+ []) xs