我想编写一个函数包,使得如何在Haskell的列表中“打包”一些字符串?
pack ['a','a','a','b','c','c','a','a','d','e','e','e']
= ["aaa","b","cc","aa","d","eee"]
我怎样才能做到这一点?我卡住了...
我想编写一个函数包,使得如何在Haskell的列表中“打包”一些字符串?
pack ['a','a','a','b','c','c','a','a','d','e','e','e']
= ["aaa","b","cc","aa","d","eee"]
我怎样才能做到这一点?我卡住了...
这里的东西从我的头顶:
pack :: (Eq a) => [a] -> [[a]]
pack [] = []
-- We split elements of a list recursively into those which are equal to the first one,
-- and those that are not. Then do the same for the latter:
pack (x:xs) = let (first, rest) = span (==x) xs
in (x:first) : pack rest
Data.List已经有你在找什么,但。
λ> import Data.List (group)
λ> :t group
group :: Eq a => [a] -> [[a]]
λ> group ['a','a','a','b','c','c','a','a','d','e','e','e']
["aaa","b","cc","aa","d","eee"]
除非你想要写函数自己(见Michael Foukarakis answer)
我认为这是值得加入了更明确的/初学者版本:
pack :: [Char] -> [String]
pack [] = []
pack (c:cs) =
let (v, s) = findConsecutive [c] cs
in v : pack s
where
findConsecutive ds [] = (ds, [])
findConsecutive [email protected](d:ds) [email protected](e:es)
| d /= e = (s, t)
| otherwise = findConsecutive (e:s) es
如果输入是一个空列表,结果也是一个空列表。否则,我们会找到相同的下一个连续的Char
,并将它们组合成一个String
,它将在结果列表中返回。为了做到这一点,我们使用findConsecutive
辅助功能。该函数的行为类似于takeWhile
函数,不同之处在于我们事先知道要使用的谓词(相等比较),并且我们返回已使用的列表和剩余的列表。
换句话说,的findConsecutive
签名可以写成:
findConsecutive :: String -> [Char] -> (String, String)
,这意味着它需要仅含有重复的字符的字符串被用作蓄电池和其字符是“提取”的列表从。它返回一个包含当前元素序列和其余列表的元组。它的主体应该是直观的:字符列表不是空的,当前元素等于累加器中的元素,我们将该字符添加到累加器并递归到函数中。当我们到达列表的结尾或遇到不同的字符时,该函数返回。
同样的理由可以用来理解pack
的主体。
如果您正在研究“教科书”问题,那么最好熟悉[99 Haskell问题](https://wiki.haskell.org/H-99:_Ninety-Nine_Haskell_Problems)。这是问题9,解决方案页面显示了[多种方式来执行此操作](https://wiki.haskell.org/99_questions/Solutions/9)(如每个方法一样)。 – HostileFork