重复输入列表中的每个连续元素比前一个元素多一个

时间:2015-09-07 05:04:13

标签: string list haskell

我希望输入字符串中的每个连续字符比前一个字符多一个,从第一个字符的单个匹配开始:

例如

rep "abcd" == "abbcccdddd"

我执行了此代码,但这不适用于String,但会为IntChar生成正确的结果。

rep [] =[]
rep (x:xs) =[ (x:xs)!!y| y<-[0..(length xs)]  , _<- [1..y+1]]

我该如何解决这个问题?

1 个答案:

答案 0 :(得分:5)

您可以先使用列表zip列出replicate,然后应用concatconcatMap结果:

[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" !!,而不喜欢lengthmap s。

此外,我不相信上述函数可以为fold生成正确的结果,但不能为[Int]生成一个简单的原因:函数是多态的,因此通过参数化无关紧要列表包含的元素类型,只要它的长度,结果将始终具有相同的形状(如果你看到函数永远不“看”/“操作”元素,它只是移动它们;它确实完全相同的东西,独立于他们的特定类型。)