在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]
答案 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
等)。相反,您只需要知道您需要的每个数字的重复次数。您可以通过2
和1
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