-- | Functions for working with lists.
module Utils.Drasil.Lists where

import Data.List

import Data.Containers.ListUtils (nubOrd)

-- | Check if list has at least 2 elements.
atLeast2 :: [a] -> Bool
atLeast2 :: forall a. [a] -> Bool
atLeast2 (a
_:a
_:[a]
_) = Bool
True
atLeast2 [a]
_       = Bool
False

-- | Replaces all elements of a target list that belong to a provided "bad"
--   input list.
replaceAll :: Eq a => [a] -> a -> [a] -> [a]
replaceAll :: forall a. Eq a => [a] -> a -> [a] -> [a]
replaceAll [a]
bad a
repl (a
c:[a]
cs) | a
c a -> [a] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [a]
bad = a
repl a -> [a] -> [a]
forall a. a -> [a] -> [a]
: [a] -> a -> [a] -> [a]
forall a. Eq a => [a] -> a -> [a] -> [a]
replaceAll [a]
bad a
repl [a]
cs
                           | Bool
otherwise    = a
c a -> [a] -> [a]
forall a. a -> [a] -> [a]
: [a] -> a -> [a] -> [a]
forall a. Eq a => [a] -> a -> [a] -> [a]
replaceAll [a]
bad a
repl [a]
cs
replaceAll [a]
_   a
_    [a]
it                    = [a]
it

-- | Checks if the first set is a subset of the second.
subsetOf :: Eq a => [a] -> [a] -> Bool
[a]
xs subsetOf :: forall a. Eq a => [a] -> [a] -> Bool
`subsetOf` [a]
ys = (a -> Bool) -> [a] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (a -> [a] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [a]
ys) [a]
xs

-- | Sort a list, removing all duplicates
nubSort :: Ord a => [a] -> [a]
nubSort :: forall a. Ord a => [a] -> [a]
nubSort = [a] -> [a]
forall a. Ord a => [a] -> [a]
nubOrd ([a] -> [a]) -> ([a] -> [a]) -> [a] -> [a]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [a] -> [a]
forall a. Ord a => [a] -> [a]
sort

-- | Interweaves two lists together @[[a,b,c],[d,e,f]] -> [a,d,b,e,c,f]@.
weave :: [[a]] -> [a]
weave :: forall a. [[a]] -> [a]
weave = [[a]] -> [a]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat ([[a]] -> [a]) -> ([[a]] -> [[a]]) -> [[a]] -> [a]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [[a]] -> [[a]]
forall a. [[a]] -> [[a]]
transpose

-- | Fold helper function that applies f to all but the last element, applies g to
-- last element and the accumulator.
foldle :: (a -> a -> a) -> (a -> a -> a) -> a -> [a] -> a
foldle :: forall a. (a -> a -> a) -> (a -> a -> a) -> a -> [a] -> a
foldle a -> a -> a
_ a -> a -> a
_ a
z []     = a
z
foldle a -> a -> a
_ a -> a -> a
g a
z [a
x]    = a -> a -> a
g a
z a
x
foldle a -> a -> a
f a -> a -> a
g a
z [a
x,a
y]  = a -> a -> a
g (a -> a -> a
f a
z a
x) a
y
foldle a -> a -> a
f a -> a -> a
g a
z (a
x:[a]
xs) = (a -> a -> a) -> (a -> a -> a) -> a -> [a] -> a
forall a. (a -> a -> a) -> (a -> a -> a) -> a -> [a] -> a
foldle a -> a -> a
f a -> a -> a
g (a -> a -> a
f a
z a
x) [a]
xs

-- | Fold helper function that applies f to all but last element, applies g to last
-- element and accumulator without starting value, does not work for empty list.
foldle1 :: (a -> a -> a) -> (a -> a -> a) -> [a] -> a
foldle1 :: forall a. (a -> a -> a) -> (a -> a -> a) -> [a] -> a
foldle1 a -> a -> a
_ a -> a -> a
_ []       = [Char] -> a
forall a. HasCallStack => [Char] -> a
error [Char]
"foldle1 cannot be used with empty list"
foldle1 a -> a -> a
_ a -> a -> a
_ [a
x]      = a
x
foldle1 a -> a -> a
_ a -> a -> a
g [a
x,a
y]    = a -> a -> a
g a
x a
y
foldle1 a -> a -> a
f a -> a -> a
g (a
x:a
y:[a]
xs) = (a -> a -> a) -> (a -> a -> a) -> a -> [a] -> a
forall a. (a -> a -> a) -> (a -> a -> a) -> a -> [a] -> a
foldle a -> a -> a
f a -> a -> a
g (a -> a -> a
f a
x a
y) [a]
xs

-- | Convert "row" of elements into "column" of elements.
toColumn :: [a] -> [[a]]
toColumn :: forall a. [a] -> [[a]]
toColumn = (a -> [a]) -> [a] -> [[a]]
forall a b. (a -> b) -> [a] -> [b]
map (a -> [a] -> [a]
forall a. a -> [a] -> [a]
: [])