packages feed

lists 0.0.0 → 0.1.0

raw patch · 2 files changed

+259/−5 lines, 2 filesdep +split

Dependencies added: split

Files

lists.cabal view
@@ -1,5 +1,5 @@ name:                lists-version:             0.0.0+version:             0.1.0 synopsis:            Functions for dealing with lists description:         Functions for dealing with lists license:             BSD3@@ -15,5 +15,6 @@   exposed-modules:   Data.Lists   hs-source-dirs:    src/   build-depends:     base > 4 && <5,-                     bools+                     bools,+                     split   ghc-options:       -Wall
src/Data/Lists.hs view
@@ -1,18 +1,45 @@--- | Extra functions for dealing with lists.+-- | Functions for dealing with lists.  module Data.Lists-  (list+  (-- * List operations+  list   ,unionOf   ,for   ,lastToMaybe   ,firstOr   ,maxList-  ,module Data.List)+  ,powerslice+  ,merge+  ,mergeBy+  ,hasAny+  ,takeWhileList+  ,dropWhileList+  ,spanList+  ,keysAL+  ,valuesAL+  ,breakList+  ,replace+  ,joins+  ,genericJoin+  ,addToAL+  ,delFromAL+  ,hasKeyAL+  ,flipAL+  ,strToAL+  ,strFromAL+  ,countElem+  ,elemRIndex+  ,alwaysElemRIndex+  ,seqList+  -- * Re-exports+  ,module Data.List+  ,module Data.List.Split)   where  import Data.Bools import Data.List import Data.Maybe+import Data.List.Split  -- | When a list is non-null, pass it to a function, otherwise use the -- default.@@ -41,3 +68,229 @@ maxList :: (Num t, Ord t) => [t] -> t maxList [] = 0 maxList xs = maximum xs++-- | Essentially a powerset but retaining contiguously ordererd subsets.+powerslice :: [a] -> [[a]]+powerslice xs = [] : concatMap (tail . inits) (tails xs)++{- | Merge two sorted lists into a single, sorted whole.++Example:++> merge [1,3,5] [1,2,4,6] -> [1,1,2,3,4,5,6]++QuickCheck test property:++prop_merge xs ys =+    merge (sort xs) (sort ys) == sort (xs ++ ys)+          where types = xs :: [Int]+-}+merge ::  (Ord a) => [a] -> [a] -> [a]+merge = mergeBy (compare)++{- | Merge two sorted lists using into a single, sorted whole,+allowing the programmer to specify the comparison function.++QuickCheck test property:++prop_mergeBy xs ys =+    mergeBy cmp (sortBy cmp xs) (sortBy cmp ys) == sortBy cmp (xs ++ ys)+          where types = xs :: [ (Int, Int) ]+                cmp (x1,_) (x2,_) = compare x1 x2+-}+mergeBy :: (a -> a -> Ordering) -> [a] -> [a] -> [a]+mergeBy _cmp [] ys = ys+mergeBy _cmp xs [] = xs+mergeBy cmp (allx@(x:xs)) (ally@(y:ys))+        -- Ordering derives Eq, Ord, so the comparison below is valid.+        -- Explanation left as an exercise for the reader.+        -- Someone please put this code out of its misery.+    | (x `cmp` y) <= EQ = x : mergeBy cmp xs ally+    | otherwise = y : mergeBy cmp allx ys++{- | Returns true if the given list contains any of the elements in the search+list. -}+hasAny :: Eq a => [a]           -- ^ List of elements to look for+       -> [a]                   -- ^ List to search+       -> Bool                  -- ^ Result+hasAny [] _ = False             -- An empty search list: always false+hasAny _ [] = False             -- An empty list to scan: always false+hasAny search (x:xs) = if x `elem` search then True else hasAny search xs++{- | Similar to Data.List.takeWhile, takes elements while the func is true.+The function is given the remainder of the list to examine. -}+takeWhileList :: ([a] -> Bool) -> [a] -> [a]+takeWhileList _ [] = []+takeWhileList func list'@(x:xs) =+    if func list'+       then x : takeWhileList func xs+       else []++{- | Similar to Data.List.dropWhile, drops elements while the func is true.+The function is given the remainder of the list to examine. -}+dropWhileList :: ([a] -> Bool) -> [a] -> [a]+dropWhileList _ [] = []+dropWhileList func list'@(_:xs) =+    if func list'+       then dropWhileList func xs+       else list'++{- | Similar to Data.List.span, but performs the test on the entire remaining+list instead of just one element.++@spanList p xs@ is the same as @(takeWhileList p xs, dropWhileList p xs)@+-}+spanList :: ([a] -> Bool) -> [a] -> ([a], [a])++spanList _ [] = ([],[])+spanList func list'@(x:xs) =+    if func list'+       then (x:ys,zs)+       else ([],list')+    where (ys,zs) = spanList func xs++{- | Similar to Data.List.break, but performs the test on the entire remaining+list instead of just one element.+-}+breakList :: ([a] -> Bool) -> [a] -> ([a], [a])+breakList func = spanList (not . func)++{- | Given a list and a replacement list, replaces each occurance of the search+list with the replacement list in the operation list.++Example:++>replace "," "." "127,0,0,1" -> "127.0.0.1"++This could logically be thought of as:++>replace old new l = join new . split old $ l+-}++replace :: Eq a => [a] -> [a] -> [a] -> [a]+replace old new l = joins new . splitOn old $ l++{- | Given a delimiter and a list of items (or strings), join the items+by using the delimiter.++Example:++> join "|" ["foo", "bar", "baz"] -> "foo|bar|baz"+-}+joins :: [a] -> [[a]] -> [a]+joins delim l = concat (intersperse delim l)++{- | Like 'join', but works with a list of anything showable, converting+it to a String.++Examples:++> genericJoin ", " [1, 2, 3, 4] -> "1, 2, 3, 4"+> genericJoin "|" ["foo", "bar", "baz"] -> "\"foo\"|\"bar\"|\"baz\""++-}+genericJoin :: Show a => String -> [a] -> String+genericJoin delim l = joins delim (map show l)++{- | Adds the specified (key, value) pair to the given list, removing any+existing pair with the same key already present. -}+addToAL :: Eq key => [(key, elt)] -> key -> elt -> [(key, elt)]+addToAL l key value = (key, value) : delFromAL l key++{- | Removes all (key, value) pairs from the given list where the key+matches the given one. -}+delFromAL :: Eq key => [(key, a)] -> key -> [(key, a)]+delFromAL l key = filter (\a -> (fst a) /= key) l++{- | Returns the keys that comprise the (key, value) pairs of the given AL.++Same as:++>map fst+-}+keysAL :: [(key, a)] -> [key]+keysAL = map fst++{- | Returns the values the comprise the (key, value) pairs of the given+AL.++Same as:++>map snd+-}+valuesAL :: [(a, value)] -> [value]+valuesAL = map snd++{- | Indicates whether or not the given key is in the AL. -}+hasKeyAL :: Eq a => a -> [(a, b)] -> Bool+hasKeyAL key list' =+    elem key (keysAL list')++{- | Flips an association list.  Converts (key1, val), (key2, val) pairs+to (val, [key1, key2]). -}+flipAL :: (Eq key, Eq val) => [(key, val)] -> [(val, [key])]+flipAL oldl =+    let worker :: (Eq key, Eq val) => [(key, val)] -> [(val, [key])] -> [(val, [key])]+        worker [] accum = accum+        worker ((k, v):xs) accum =+            case lookup v accum of+                                Nothing -> worker xs ((v, [k]) : accum)+                                Just y -> worker xs (addToAL accum v (k:y))+        in+        worker oldl []++{- | Converts an association list to a string.  The string will have+one pair per line, with the key and value both represented as a Haskell string.++This function is designed to work with [(String, String)] association lists,+but may work with other types as well. -}++strFromAL :: (Show a, Show b) => [(a, b)] -> String+strFromAL inp =+    let worker (key, val) = show key ++ "," ++ show val+        in unlines . map worker $ inp++{- | The inverse of 'strFromAL', this function reads a string and outputs the+appropriate association list.++Like 'strFromAL', this is designed to work with [(String, String)] association+lists but may also work with other objects with simple representations.+-}+strToAL :: (Read a, Read b) => String -> [(a, b)]+strToAL inp =+    let worker line =+            case reads line of+               [(key, remainder)] -> case remainder of+                     ',':valstr -> (key, read valstr)+                     _ -> error "Data.List.Utils.strToAL: Parse error on value"+               _ -> error "Data.List.Utils.strToAL: Parse error on key"+        in map worker (lines inp)+++{- FIXME TODO: sub -}++{- | Returns a count of the number of times the given element occured in the+given list. -}+countElem :: Eq a => a -> [a] -> Int+countElem i = length . filter (i==)++{- | Returns the rightmost index of the given element in the+given list. -}+elemRIndex :: Eq a => a -> [a] -> Maybe Int+elemRIndex item l =+    case reverse $ elemIndices item l of+      [] -> Nothing+      (x:_) -> Just x++{- | Like elemRIndex, but returns -1 if there is nothing+found. -}+alwaysElemRIndex :: Eq a => a -> [a] -> Int+alwaysElemRIndex item list' =+    case elemRIndex item list' of+       Nothing -> -1+       Just x -> x++{- | Forces the evaluation of the entire list. -}+seqList :: [a] -> [a]+seqList [] = []+seqList list'@(_:xs) = seq (seqList xs) list'