module Zora.List
(
uniqueify
, pairify
, decyclify
, shuffle
, powerset
, gen_perms
, gen_subsets_of_size
, gen_cycles
, has_cycles
, partition_with_block_size
, partition_into_k
, powerpartition
, diff_infinite
, merge
, merge_by
, zip_while
, remove_at_index
, subseq
, take_while_keep_last
, take_while_and_rest
, is_sorted
, mergesort
, is_palindrome
, contains_duplicates
, map_keep
, maximum_with_index
, length'
, drop'
, take'
, cons
, snoc
) where
import qualified Data.List as List
import qualified Data.Ord as Ord
import qualified Data.Set as Set
import System.Random
import Data.Monoid
import Data.Maybe
uniqueify :: (Ord a) => [a] -> [a]
uniqueify = Set.elems . Set.fromList
pairify :: [a] -> [(a, a)]
pairify l@(a:b:l') = (a, b) : pairify l'
pairify l = []
decyclify :: (Eq a) => [a] -> [a]
decyclify = fromJust . List.find (not . has_cycles) . iterate decyclify_once
decyclify_once :: (Eq a) => [a] -> [a]
decyclify_once l =
if isNothing lambda
then l
else take' (lambda' + mu'') l
where
i = alg1 (tail l) (tail . tail $ l)
i' = fromJust i
mu = if (i == Nothing) then Nothing else alg2 l (drop' i' l)
mu' = fromInteger . fromJust $ mu
mu'' = fromJust mu
lambda = if (mu == Nothing) then Nothing else alg3 (drop (mu' + 1) l) (l !! mu')
lambda' = fromJust lambda
alg1' :: (Eq a) => Integer -> [a] -> [a] -> Maybe Integer
alg1' i _ [] = Nothing
alg1' i [] _ = Nothing
alg1' i l1 l2 =
if (head l1) == (head l2) then
Just (i + 1)
else
if tail l2 == [] then
Nothing
else
alg1' (i + 1) (tail l1) (tail . tail $ l2)
alg2' :: (Eq a) => Integer -> [a] -> [a] -> Maybe Integer
alg2' mu _ [] = Nothing
alg2' mu [] _ = Nothing
alg2' mu l1 l2 =
if (head l1) == (head l2) then
Just mu
else
alg2' (mu + 1) (tail l1) (tail l2)
alg3' :: (Eq a) => Integer -> [a] -> a -> Maybe Integer
alg3' lambda [] e = Nothing
alg3' lambda l e =
if (head l) == e then
Just lambda
else
alg3' (lambda + 1) (tail l) e
alg1 :: (Eq a) => [a] -> [a] -> Maybe Integer
alg1 = alg1' 0
alg2 :: (Eq a) => [a] -> [a] -> Maybe Integer
alg2 = alg2' 0
alg3 :: (Eq a) => [a] -> a -> Maybe Integer
alg3 = alg3' 1
shuffle' :: [a] -> [Integer] -> [a]
shuffle' l indices =
map fst . List.sortBy (Ord.comparing snd) $ zip l indices
shuffle :: forall a. (Eq a) => [a] -> Integer -> [a]
shuffle l seed = shuffle' l randomness
where
randomness :: [Integer]
randomness = prep (length' l) $ random_integers (0, (length' l) 1) seed
random_integers :: (Integer, Integer) -> Integer -> [Integer]
random_integers range = randomRs range . mkStdGen . fromInteger
prep :: Integer -> [Integer] -> [Integer]
prep len l' = reverse . take' len $ prep' l' []
prep' :: [Integer] -> [Integer] -> [Integer]
prep' [] seen = []
prep' src seen =
if head src `elem` seen
then prep' (tail src) seen
else head src : (prep' (tail src) (head src : seen))
powerset :: [a] -> [[a]]
powerset l = powerset_rec l []
where
powerset_rec :: [a] -> [a] -> [[a]]
powerset_rec [] so_far = [so_far]
powerset_rec src so_far = without ++ with
where without = powerset_rec (tail src) (so_far)
with = powerset_rec (tail src) ((head src) : so_far)
gen_perms :: [a] -> [[a]]
gen_perms l
| (length l <= 1) = [l]
| otherwise =
let splice_pairs = [(l !! i, remove_at_index (toInteger i) l) | i <- [0..((length l) 1)]]
in
concat [
[fst splice_pair : recpair | recpair <- gen_perms $ snd splice_pair]
| splice_pair <- splice_pairs
]
gen_subsets_of_size :: [a] -> Integer -> [[a]]
gen_subsets_of_size l size = gen_subsets_of_size_rec l [] size
where
gen_subsets_of_size_rec :: [a] -> [a] -> Integer -> [[a]]
gen_subsets_of_size_rec src so_far size =
if size == 0
then [so_far]
else if (length src) == 0
then []
else without ++ with
where
without = gen_subsets_of_size_rec (tail src) so_far size
with = gen_subsets_of_size_rec (tail src) ((head src) : so_far) (size1)
gen_cycles :: (Eq a) => [a] -> [[a]]
gen_cycles l = gen_cycles_rec l $ cycle_list l
where
cycle_list :: [a] -> [a]
cycle_list l = (tail l) ++ [head l]
gen_cycles_rec :: (Eq a) => [a] -> [a] -> [[a]]
gen_cycles_rec original_l l
| l == original_l = [l]
| otherwise = [l] ++ (gen_cycles_rec original_l $ cycle_list l)
has_cycles :: (Eq a) => [a] -> Bool
has_cycles l = (decyclify_once l) /= l
partition_with_block_size :: Int -> [a] -> [[a]]
partition_with_block_size len l =
if (length l) <= len
then [l]
else (take len l) : (partition_with_block_size len (drop len l))
partition_into_k :: Int -> [a] -> [[a]]
partition_into_k k arr = partition_with_block_size block_size arr
where
block_size :: Int
block_size = if (((length arr) `mod` k) == 0)
then (length arr) `div` k
else (length arr) `div` k + 1
powerpartition :: [a] -> [[[a]]]
powerpartition [] = []
powerpartition l@(x:xs) =
if length l == 1
then [[[x]]]
else concatMap (get_next_partitions x) . powerpartition $ xs
where
get_next_partitions :: a -> [[a]] -> [[[a]]]
get_next_partitions e l = ([e] : l) : (map f indices)
where
f i = (a i) ++ (b i) ++ (c i)
a i = ((take' i) l)
b i = [e : (l !! (fromInteger i))]
c i = (drop' (i+1) l)
indices = [0..((length' l) 1)]
diff_infinite :: (Ord a) => [a] -> [a] -> [a]
diff_infinite xs@(x:xt) ys@(y:yt) =
case compare x y of
LT -> x : (diff_infinite xt ys)
EQ -> diff_infinite xt yt
GT -> diff_infinite xs yt
merge :: (Ord a) => [a] -> [a] -> [a]
merge = merge_by compare
merge_by :: (Ord a) => (a -> a -> Ordering) -> [a] -> [a] -> [a]
merge_by cmp as bs
| length as == 0 = bs
| length bs == 0 = as
| otherwise =
let
a = head as
b = head bs
as' = tail as
bs' = tail bs
in
case cmp a b of
LT -> a : merge_by cmp as' bs
EQ -> a : merge_by cmp as' bs
GT -> b : merge_by cmp as bs'
zip_while :: (a -> b -> Bool) -> [a] -> [b] -> [(a, b)]
zip_while f as bs = takeWhile (\(a, b) -> f a b) $ zip as bs
remove_at_index :: Integer -> [a] -> [a]
remove_at_index i l =
let a = fst $ splitAt (fromInteger i) l
b = snd $ splitAt (fromInteger i) l
in a ++ tail b
subseq :: Integer -> Integer -> [a] -> [a]
subseq i len = take (fromInteger len) . drop (fromInteger i)
take_while_keep_last :: (a -> Bool) -> [a] -> [a]
take_while_keep_last f [] = []
take_while_keep_last f (x:xs) =
if f x
then [x]
else x : take_while_keep_last f xs
take_while_and_rest :: (a -> Bool) -> [a] -> ([a], [a])
take_while_and_rest f [] = ([], [])
take_while_and_rest f l@(x:xs) = if not . f $ x
then ([], l)
else (x:(fst rec), snd rec)
where
rec = take_while_and_rest f xs
is_sorted :: (Ord a) => [a] -> Bool
is_sorted l = and $ zipWith (<=) l (tail l)
mergesort :: (Ord a) => [a] -> [a]
mergesort l =
if length l <= 1
then l
else merge (mergesort a) (mergesort b)
where
(a, b) = splitAt (floor ((fromIntegral $ length l) / 2)) l
is_palindrome :: (Eq e) => [e] -> Bool
is_palindrome s =
if length s <= 1
then True
else (head s == last s) && (is_palindrome $ tail . init $ s)
contains_duplicates :: forall a . (Ord a) => [a] -> Bool
contains_duplicates l =
if is_sorted l
then or $ zipWith (==) l (tail l)
else isNothing $ foldr insert (Just Set.empty) l
where
insert :: a -> Maybe (Set.Set a) -> Maybe (Set.Set a)
insert a s = if isNothing s
then Nothing
else if Set.member a (fromJust s)
then Nothing
else Just (Set.insert a (fromJust s))
map_keep :: (a -> b) -> [a] -> [(a, b)]
map_keep f l = zipWith (\a b -> (a, b)) l (map f l)
length' :: [a] -> Integer
length' = toInteger . length
drop' :: Integer -> [a] -> [a]
drop' = drop . fromInteger
take' :: Integer -> [a] -> [a]
take' = take . fromInteger
cons :: a -> [a] -> [a]
cons = (:)
snoc :: a -> [a] -> [a]
snoc e l = l ++ [e]
maximum_with_index :: (Ord a) => [a] -> (a, Integer)
maximum_with_index xs =
List.maximumBy (Ord.comparing fst) (zip xs [0..])
minimum_with_index :: (Ord a) => [a] -> (a, Integer)
minimum_with_index xs =
List.minimumBy (Ord.comparing fst) (zip xs [0..])