Haskell - 根据列表索引重复列表的元素

Pal*_*Pal 5 haskell list replicate

我仍然是Haskell的初学者.我尝试做一些模式匹配.我想重复列表中的每个元素n次.N由列表中每个元素的索引位置确定.比如['1', '2', '3']应该给我:['1', '2', '2', '3', '3', '3'].这是一个练习,我不应该使用prebuild-list-functions.

我试过这样的事情:

test [] = []
test (first:[]) = [first] 
test (first:second:rest) = first : second : test (second:rest)
Run Code Online (Sandbox Code Playgroud)

但它只是在第一个元素后加倍了每个元素.我想到elemIndex并复制但我不应该使用这些功能.我的想法是使用elemIndex并使用它作为我的"n"并使用复制或类似之后的"n"和递归.在模式匹配中我需要类似的东西.但我想,我觉得太复杂了.有没有人有想法?

Sil*_*olo 6

Haskell的一个重要部分是将问题分解为更小的问题.所以让我们打破你的问题吧.

你需要做的一件事就是重复一个元素.正如您已经发现的,此功能以Haskell的形式存在于replicate函数中.但你可以轻松地自己实现它.

repeatNTimes :: Int -> a -> [a]
repeatNTimes 0 _ = []
repeatNTimes n x = x : repeatNTimes (n - 1) x
Run Code Online (Sandbox Code Playgroud)

如果我们重复零次,请返回空列表.否则,将元素放在前面并递归.

现在我们可以重复一些事情 让我们编写一个跟踪列表位置的函数.它看起来像这样.

testImpl :: Int -> [a] -> [a]
Run Code Online (Sandbox Code Playgroud)

它将获取一个整数(当前位置)和列表的尾部,并返回给定该列表的特定部分的结果.和以前一样,我们有两种情况:一种是列表为空,另一种是不是.第一种情况很简单; 如果列表为空,则返回空列表.如果列表非空,请重复第一个元素,然后递归.

testImpl :: Int -> [a] -> [a]
testImpl _ [] = []
testImpl n (x:xs) = repeatNTimes n x ++ testImpl (n + 1) xs
Run Code Online (Sandbox Code Playgroud)

++是一个内置函数,它连接两个列表.如果你真的想要,你也可以自己实现.现在,首先,我们考虑的第一个元素是元素1,因为我们要重复一次,因此我们将通过传递开始递归1testImpl.

test :: [a] -> [a]
test = testImpl 1
Run Code Online (Sandbox Code Playgroud)

完整的例子:

repeatNTimes :: Int -> a -> [a]
repeatNTimes 0 _ = []
repeatNTimes n x = x : repeatNTimes (n - 1) x

testImpl :: Int -> [a] -> [a]
testImpl _ [] = []
testImpl n (x:xs) = repeatNTimes n x ++ testImpl (n + 1) xs

test :: [a] -> [a]
test = testImpl 1
Run Code Online (Sandbox Code Playgroud)