我希望输入字符串中的每个连续字符比前一个字符多一个,从第一个字符的单个匹配开始:
例如
rep "abcd" == "abbcccdddd"
我执行了此代码,但这不适用于String
,但会为Int
和Char
生成正确的结果。
rep [] =[]
rep (x:xs) =[ (x:xs)!!y| y<-[0..(length xs)] , _<- [1..y+1]]
我该如何解决这个问题?
答案 0 :(得分:5)
您可以先使用列表zip
列出replicate
,然后应用concat
和concatMap
结果:
[1..]
示例运行:
rep xs = concatMap (uncurry replicate) $ zip [1..] xs
这个想法很简单,我们将每个元素与它应该重复的次数联系起来。
Prelude> let rep xs = concatMap (uncurry replicate) $ zip [1..] xs
Prelude> rep "abcd"
"abbcccdddd"
函数具有类型zip
,因此它需要两个列表并返回一个对列表,其中第一个元素来自第一个列表,第二个元素来自第二个列表。在我们的例子中,我们得到的结果是[a] -> [b] -> [(a, b)]
类型[(Int, a)]
,具体取决于参数。
a
函数采用一个表示长度和元素replicate :: Int -> a -> [a]
的整数,并生成给定长度的列表x
。
[x, x, x, ..., x]
函数接受类型为uncurry
的函数,即带有两个参数,并将其转换为类型为a -> b -> c
的函数,即一个参数为元组。因此(a, b) -> c
的类型为uncurry replicate
。
现在类型匹配,你可以(Int, a) -> [a]
map
ed列表中的函数获得zip
,然后使用[[a]]
连接结果。 zipWith
只是concat
的缩写。
另外,您可以使用when.js函数代替concat . map
然后使用zip
:
map
请注意,您的解决方案似乎正常运行:
rep xs = concat $ zipWith replicate [1..] xs
如果您有一个不能产生正确结果的示例,请将其发布在您的问题中。
但效率低下。在处理列表时,您应该避免使用Prelude> let rep [] = []; rep (x:xs) = [ (x:xs)!! y | y <- [0..length xs], _<-[1..y+1]]
Prelude> rep [1,2,3]
[1,2,2,3,3,3]
Prelude> rep "abcd"
"abbcccdddd"
和!!
,而不喜欢length
和map
s。
此外,我不相信上述函数可以为fold
生成正确的结果,但不能为[Int]
生成一个简单的原因:函数是多态的,因此通过参数化无关紧要列表包含的元素类型,只要它的长度,结果将始终具有相同的形状(如果你看到函数永远不“看”/“操作”元素,它只是移动它们;它确实完全相同的东西,独立于他们的特定类型。)