我需要编写一个带有gggggggeeeeetttttt字符串的函数,并且可以计算字母重复和输出的次数为g7e5t6。
我刚刚开始使用Haskell,所以不确定从哪里开始。
答案 0 :(得分:13)
函数group
将列表中的相同元素组合在一起。由于字符串是一个字符列表,我们有:
group "ggggeeetttt" = ["gggg","eee","tttt"]
要收到这封信,我们可以使用map head
,因为head
接受字符串(或任何列表)的第一个元素:
map head ["gggg","eee","tttt"] = ['g','e','t']
现在,我们想知道每个子字符串中有多少个元素。这可以使用map length
:
map length ["gggg","eee","tttt"] = [4,3,4]
让我们将这些数字转回字符串:
map show [4,3,4] = ["4","3","4"]
现在我们需要以某种方式组合原始列表和长度列表。我们可以这样做:
zipWith (:) ['g','e','t'] ["4","3","4"]
zipWith
会将指定的函数应用于两个列表中的配对元素。在这里,我使用了(:)
,它在列表的开头添加了一个元素。
这为您提供了完成所需操作所需的所有构建块。例如,这应该有效,尽管我还没有测试过:
f s = concat $ zipWith (:) letters lengths
where
groups = group s
letters = map head groups
lengths = map (show . length) groups
答案 1 :(得分:7)
变异与理解,有点漂亮(考虑以前的解释只是代码):
ghci> let s = "gggggggeeeeetttttt"
ghci> putStrLn $ concat [head g: show (length g) | g <- group s]
g7e5t6
答案 2 :(得分:3)
最好的开始方式是弄清楚你的问题。我建议采用以下方法:
String
并返回一个字符串列表([String]
)。splitStr "gggggggeeeeetttttt"
应返回["ggggggg","eeeee","tttttt"]
Data.List
已经提供了这样一个函数,它名为group
。length
。head
。例如。 head "abc"
会产生'a'
要将它固定在长度的前面,你可以使用一个小的辅助函数和show
,它将大多数东西变成一个字符串。我们的助手看起来像这样:makeRepetitions string = head string : show (length string)
。 :
aka cons在列表的前面添加了一个元素。map
。 map
将函数应用于值列表并返回结果列表concat
。实际上,我们可以使用concatMap
来组合(4)和(5)。此函数将函数映射到值列表并将结果连接起来 - 就像我们想要的那样。现在,您的代码如下所示:
import Data.List
runlength :: String -> String
runlength string = concatMap makeRepetitions (group string)) where
makeRepetitions string = head string : show (length string)
因为很多括号很烦人,Haskellers经常使用.
。点结合了两个函数来创建一个新函数。您可以认为f = functionA . functionB
等于f x = functionA (functionB x)
。使用点,我们可以重新格式化程序:
import Data.List
runlength :: String -> String
runlength = concatMap makeRepetitions . group where
makeRepetitions string = head string : show (length string)
IMO,这种表示更具可读性。您可以将runlength
视为管道。首先应用group
,然后我们使用concatMap
将makeRepetitions
映射到输入上并连接结果。
答案 3 :(得分:1)
滥用箭头和无点:)
f = group >>> concatMap (head &&& (show . length) >>> uncurry (:))
这是适用的:
f = concatMap ((:) <$> head <*> (show . length)) . group