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

yes*_*era 2 string haskell list

我想在输入字符串中重复每个连续字符多于前一个字符,从第一个字符的单个匹配开始:

例如

rep "abcd" == "abbcccdddd"
Run Code Online (Sandbox Code Playgroud)

我做了这个代码,但这不起作用,String但为Int和产生正确的结果Char.

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

我怎样才能解决这个问题?

Bak*_*riu 5

您可以首先zip列出[1..]您的列表,然后应用replicateconcat结果:

rep xs = concatMap (uncurry replicate) $ zip [1..] xs
Run Code Online (Sandbox Code Playgroud)

示例运行:

Prelude> let rep xs = concatMap (uncurry replicate) $ zip [1..] xs
Prelude> rep "abcd"
"abbcccdddd"
Run Code Online (Sandbox Code Playgroud)

这个想法很简单,我们将每个元素与它应该重复的次数联系起来.

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通过ziped列表获取a [[a]]然后使用concat来连接结果.concatMap只是简写concat . map.

或者,而不是使用zip然后map你可以使用该zipWith功能:

rep xs = concat $ zipWith replicate [1..] xs
Run Code Online (Sandbox Code Playgroud)

请注意,您的解决方案似乎正常工作:

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"
Run Code Online (Sandbox Code Playgroud)

如果您有一个不能产生正确结果的示例,请将其发布在您的问题中.

然而,这是低效的.你应该避免使用!!length使用列表时更喜欢map和喜欢的东西fold.

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

  • `rep = concat.zipWith replicate [1 ..]`有点短. (2认同)