偶数索引上列表的重复元素

时间:2018-06-08 10:39:39

标签: haskell functional-programming

在Haskell中,我如何实现一个函数dup,它复制列表中偶数位置(0,2,4 ......)上的所有元素

dup :: [a] -> [a]
dup [] = []
dup (x:xs) =  x : x : dup xs
//but only on even index ??

电话示例:

dup [1,5,2,8,4] = [1,1,5,2,2,8,4,4]

3 个答案:

答案 0 :(得分:4)

我们可以定义两个执行相互递归的函数:dupeven :: [a] -> [a]dupodd :: [a] -> [a]。因此,dupeven将复制第一个元素,并递归传递给dupodd。另一方面,dupodd只生成头部的一个副本,然后在dupeven上执行递归。像:

dupeven :: [a] -> [a]
dupeven [] = []
dupeven (x:xs) = x : x : dupodd xs

dupodd :: [a] -> [a]
dupodd [] = []
dupodd (x:xs) = x : dupeven xs

好消息是我们得到两个重复的变种。此外,这两个函数都相当简单:它们只对两个不同的模式进行操作:空列表[]和"缺点" (:)

因此按预期工作,而且我们基本上还有一个额外的功能(相当)低实现成本:

Prelude> dupeven [1,5,2,8,4]
[1,1,5,2,2,8,4,4]
Prelude> dupodd [1,5,2,8,4]
[1,5,5,2,8,8,4]

答案 1 :(得分:4)

正如其他答案所解释的那样,你可以从第一原则递归地编写这个函数,但我总是认为这些问题是有趣的难题:如何从现有的基础库中编写这样的函数? < / p>

首先,每当你想索引一个列表时,你可以zip使用一个懒惰的评估无限列表:

Prelude> zip [0..] [1,5,2,8,4]
[(0,1),(1,5),(2,2),(3,8),(4,4)]

在这种情况下,您实际上并不需要知道实际的索引值(0, 1, 2, 3, 4等)。相反,您只需要知道您需要的每个数字的重复次数。您可以通过21

无限循环来产生这些知识
Prelude> take 10 $ cycle [2,1]
[2,1,2,1,2,1,2,1,2,1]

(上面的示例使用take 10来停止对列表的评估,否则,将继续评估列表。)

您可以zip (cycle [2,1])使用任何输入列表来获取元组列表:

Prelude> zip (cycle [2,1]) [1,5,2,8,4]
[(2,1),(1,5),(2,2),(1,8),(2,4)]

元组的第一个元素是重复第二个元素的次数。

您可以使用replicate多次重复任何值,但您必须uncurry才能将单个元组作为输入:

Prelude> uncurry replicate (2,1)
[1,1]
Prelude> uncurry replicate (1,5)
[5]

请注意,此函数始终返回一个列表,因此如果您在元组列表上执行此操作,则会有一个列表列表。要立即展平这样的列表,您可以使用monadic bind来展平投影:

Prelude> zip (cycle [2,1]) [1,5,2,8,4] >>= uncurry replicate
[1,1,5,2,2,8,4,4]

如果愿意,你可以用它来制作一个功能:

dup xs = zip (cycle [2,1]) xs >>= uncurry replicate

这个函数结果是参数多态的,所以当你可以将它与整数列表一起使用时,你也可以将它与字符列表一起使用:

Prelude> dup [1,5,2,8,4]
[1,1,5,2,2,8,4,4]
Prelude> dup "acen"
"aaceen"

答案 2 :(得分:2)

您可能想要创建一个相互递归的函数集

duplicate, duplicate' :: [a] -> [a]
duplicate [] = []
duplicate (x:xs) =  x : x : duplicate' xs
duplicate' [] = []
duplicate' (x:xs) = x : duplicate xs

或者添加一个简单的ADT来确定下一个动作

data N = O | T
duplicate = duplicate' T
duplicate' _ [] = []
duplicate' T (x:xs) = x : x : duplicate' O xs
duplicate' O (x:xs) = x : duplicate' T xs

但说实话,最好的办法是@Simon_Shine建议,

duplicate [] = []
duplicate (x:y:xs) = x : x : y : duplicate xs
duplicate (x:xs) = x : x : xs -- Here x is an even index and xs is an empty list