module ListUtils (listByFrequency, count, bidirect, bidirectionalAccessor1D, bidirectionalAccessor2D, monodirect, monodirectionalList1D, monodirectionalList2D, cachedAccessor1D, cachedAccessor2D) where import Data.List import SegHopList -- | -- Converts a list of elements to an infinite list of those same elements such -- that the frequency of an element of the result is related to how early -- that element occurs in the parameter. Each subsequent element in the parameter -- occurs half as often (and first occurs twice as late) as the one before. -- [a,b,c,d] becomes (cycle [a,b,a,c,a,b,a,d]) -- listByFrequency :: [a] -> [a] listByFrequency (x:[]) = repeat x listByFrequency (x:xs) = x : (intersperse x $ listByFrequency xs) listByFrequency [] = error "Can't do anything with an empty list." -- | -- count 1 [2,5,1,4,1,1] is 3, because 1 occurs three times. -- count :: Eq a => a -> [a] -> Integer count element lst = genericLength $ elemIndices element lst -- | -- Maps integers in the range [-inf .. inf] to [0 .. inf] -- bidirect :: Integer -> Integer bidirect n = if n >= 0 then (2*n) else (2*(-n)-1) -- | -- Inverse operation of bidirect. -- monodirect :: Integer -> Integer monodirect n = if (even n) then n `div` 2 else -(n `div` 2) -- | -- Accessor to reference a one-dimensional list as a bidirectional list. -- In other words, the indexes becomes: -- [0,-1,1,-2,2,-3,3,-4,4,-5,5 ...] -- bidirectionalAccessor1D :: [a] -> (Integer -> a) bidirectionalAccessor1D xs = let sh_list = SegHopList.fromList xs in (\i -> sh_list `SegHopList.index` (bidirect i)) -- | -- Accessor to reference a two-dimensional list as a bidirectional two-dimensional list. -- The outer list is considered to be the y-axis, and the inner list the x-axis, if -- elements are references by (x,y) -- bidirectionalAccessor2D :: [[a]] -> ((Integer,Integer) -> a) bidirectionalAccessor2D xss = let sh_lists = SegHopList.fromList $ map SegHopList.fromList xss in (\(x,y) -> (sh_lists `SegHopList.index` (bidirect y)) `SegHopList.index` (bidirect x)) -- | -- Inverse operation of bidirectionalAccessor1D -- monodirectionalList1D :: (Integer -> a) -> [a] monodirectionalList1D fn = map (fn . monodirect) [0..] -- | -- Inverse operation of bidirectionalAccessor2D -- monodirectionalList2D :: ((Integer,Integer) -> a) -> [[a]] monodirectionalList2D fn = let zero_dot_dot = [0..] pairs = [[(monodirect x,monodirect y) | x <- zero_dot_dot] | y <- zero_dot_dot] in map (map fn) pairs -- | -- Combines monodirectionalList1D and bidirectionalAccessor1D to create a cached version -- of the original function. If the original was a sufficiently expensive function for which -- the same value is queried many times, then the cached version may be faster, at the expense -- of memory. cachedAccessor1D :: (Integer -> a) -> (Integer -> a) cachedAccessor1D = bidirectionalAccessor1D . monodirectionalList1D -- | -- 2D version of cachedAccessor1D. -- cachedAccessor2D :: ((Integer,Integer) -> a) -> ((Integer,Integer) -> a) cachedAccessor2D = bidirectionalAccessor2D . monodirectionalList2D