指定通过将相同的连续元素转换为按元素对的数字来压缩列表的函数。组函数可能很有用。
指定从压缩列表中恢复原始文件的函数。复制功能可能很有用。
import Data.List
compress :: (Eq a, Integral b) => [a] -> [(b, a)]
compress l = zip (length $ group l) (head $ group l)
Or:
compress :: (Eq a, Integral b) => [a] -> [(b, a)]
compress [] = []
compress (x:xs)
| x == a = (b+1,a) : xs
| otherwise = (1,a) : compress (b,a) xs
decompress :: (Eq a, Integral b) => [(b, a)] -> [a]
decompress l = concat [replicate (fst x) (snd x) | x <- l]
Examples:
compress "aaaabccaadeeee" == [(4, 'a'), (1, 'b'), (2, 'c'), (2, 'a'), (1, 'd'), (4, 'e')]
compress "oh hello !!" == [(1, 'o'), (1, 'h'), (1, ''), (1, 'h'), (1, 'e'), (2, 'l'), (1, 'o'), (2, '!')]
compress [] == []
compress [1,1,0,0,0,1,1,1] == [(2.1), (3.0), (3.1)]
decompress [(4, 'a'), (1, 'b'), (2, 'c'), (2, 'a'), (1, 'd'), (4, 'e')] == "aaaabccaadeeee"
decompress [(1, 'o'), (1, 'h'), (1, ''), (1, 'h'), (1, 'e'), (2, 'l'), ( 1, 'o'), (2, '!')] == "oh hello !!"
decompress [] == []
decompress [(2,1), (3,0), (3,1)] == [1,1,0,0,0,1,1,1]
您在这里对group
的结果进行了两次枚举。您可以简化此过程,并使用映射函数将组结果的每个项转换为2元组,例如使用(&&&) :: Arrow a => a b c -> a b c' -> a b (c, c')
length :: Foldable f => f a -> Int
返回一个Int
,因此不能使用任何Integral
类型:
import Control.Arrow((&&&))
compress :: Eq a => [a] -> [(Int, a)]
compress = map (length &&& head) . group
对于解压缩,我们可以使用concatMap :: Foldable t => (a -> [b]) -> t a -> [b]
并使用uncurry :: (a -> b -> c) -> (a, b) -> c
来创建一个适用于2元组的replicate
变体replicate :: Int -> a -> [a]
适用于Int
,而不是任何Integral
,并且Eq
类型约束在这里是而不是必需的,因为我们可以复制任何项。concatMap
可以在任何Foldable
上工作,因此我们可以将类型签名推广为:
decompress :: Foldable f => f (Int, a) -> [a]
decompress = concatMap (uncurry replicate)