AERN-Basics-2011.1: src/Numeric/AERN/Misc/List.hs
{-|
Module : Numeric.AERN.Misc.List
Description : miscellaneous list functions
Copyright : (c) Michal Konecny
License : BSD3
Maintainer : mikkonecny@gmail.com
Stability : experimental
Portability : portable
Miscellaneous list functions.
-}
module Numeric.AERN.Misc.List where
import qualified System.Random as R
import qualified Data.List as List
import qualified Data.Set as Set
import qualified Data.Map as Map
sortUsing :: (Ord b) => (a -> b) -> [a] -> [a]
sortUsing f =
List.sortBy compareF
where
compareF a b = compare (f a) (f b)
{-|
Eg: @combinations [[1,2,3],[4,5],[7]] = [[1,4,7], [1,5,7], [2,4,7], [2,5,7], [3,4,7], [3,5,7]]@
-}
combinations :: [[a]] -> [[a]]
combinations [] = [[]]
combinations (options : rest) =
concat $ map addHeadToAll options
where
addHeadToAll h = map (h :) restDone
restDone = combinations rest
{-|
Eg: @mergeManyLists [[1,2,3],[4,5],[7]] = [1,4,7,2,5,3]@
-}
mergeManyLists :: [[a]] -> [a]
mergeManyLists lists
| null listsNonempty = []
| otherwise =
heads ++ (mergeManyLists tails)
where
(heads, tails) = unzip $ map (\(h:t) -> (h,t)) listsNonempty
listsNonempty = filter (not . null) lists
getNDistinctSorted :: (Ord a) => Int -> Int -> [a] -> [a]
getNDistinctSorted seed n xs =
Set.toAscList $ pickUsingIndices n xsMap randomIndices
where
pickUsingIndices _ _ [] = Set.empty
pickUsingIndices n esMap (i : is)
| Map.null esMap = Set.empty
| n > 0 =
case Map.lookup i esMap of
Nothing -> pickUsingIndices n esMap is
Just e -> Set.insert e $ (pickUsingIndices (n-1) (Map.delete i esMap) is)
| otherwise = Set.empty
randomIndices =
map (`mod` (Map.size xsMap)) $
map fst $
drop 13 $ iterate (R.next . snd) (0,g)
g = R.mkStdGen seed
xsMap = Map.fromAscList $ zip [0..] $ Set.toList $ Set.fromList xs
nubSorted :: (Eq a) => [a] -> [a]
nubSorted [] = []
nubSorted (x : xs) =
aux x xs
where
aux x [] = [x]
aux x (y : ys)
| x == y = aux x ys
| otherwise = x : (aux y ys)
{-|
Like 'zip' except if the lists are non-empty and of different length,
fill the shorter list with sufficient copies of
its last element to make the lists of equal length.
Eg @zipFill [1,2,3] [4] = [(1,4),(2,4),(3,4)]@
-}
zipFill :: [a] -> [b] -> [(a,b)]
zipFill [] list2 = []
zipFill list1 [] = []
zipFill [h1] list2 = map (\h2 -> (h1,h2)) list2
zipFill list1 [h2] = map (\h1 -> (h1,h2)) list1
zipFill (h1:t1) (h2:t2) = (h1,h2) : (zipFill t1 t2)
{-|
Like 'zip' except if the lists are non-empty and of different lengths,
fill each of the shorter lists with sufficient copies of
its last element to make all the lists of equal length.
Eg: @zipFill3 [1,2,3] [4,5] [6] = [(1,4,6),(2,5,6),(3,5,6)]@
-}
zipFill3 :: [a] -> [b] -> [c] -> [(a,b,c)]
zipFill3 [] list2 list3 = []
zipFill3 list1 [] list3 = []
zipFill3 list1 list2 [] = []
zipFill3 [h1] [h2] list3 = map (\h3 -> (h1,h2,h3)) list3
zipFill3 [h1] list2 [h3] = map (\h2 -> (h1,h2,h3)) list2
zipFill3 list1 [h2] [h3] = map (\h1 -> (h1,h2,h3)) list1
zipFill3 [h1] list2 list3 = map (\(h2,h3) -> (h1,h2,h3)) $ zipFill list2 list3
zipFill3 list1 [h2] list3 = map (\(h1,h3) -> (h1,h2,h3)) $ zipFill list1 list3
zipFill3 list1 list2 [h3] = map (\(h1,h2) -> (h1,h2,h3)) $ zipFill list1 list2
zipFill3 (h1:t1) (h2:t2) (h3:t3) = (h1,h2,h3) : (zipFill3 t1 t2 t3)