如何递归调用列表长度的函数?

时间:2014-11-03 16:36:16

标签: list haskell recursion

我有一个面试问题,从那以后一直困扰着我。

我有一个函数,fill,它执行计算就像取两个列表然后替换第二个列表中的2s,其中第一个列表中有2个,并且第一个列表中的第二个列表中也填充了2个,然后它可以流动直到遇到1。例如:

传递了两个列表[2,1,2,1,2] [0,0,1,0,0],因此我得到的输出是[2,2,1,2,2]。现在,我想写一个带有这样的参数的函数:[[2,1,2,1,2],[0,0,1,0,0],[0,0,0,0,0]],我想递归地应用我的上面的函数,直到这个列表列表的末尾。因此,首先将[2,1,2,1,2] [0,0,1,0,0]传递给填充,然后它应该得到结果[2,2,1,2,2],然后应传递[2,2,1,2,2][0,0,0,0,0],得到结果{ {1}}。我怎么能这样做?

编辑:

我这样做了:

[2,2,2,2,2]

2 个答案:

答案 0 :(得分:0)

所以,你有你的功能fill

fill :: [Int] -> [Int] -> [Int]

你想把它变成一个带有列表列表的函数:

fillRec :: [[Int]] -> [Int]

这是折叠的自然情况。这使用组合函数重复“折叠”列表的每个元素。我们需要确保列表不为空:

fillRec [] = []
fillRec (x : xs) = foldl fill x xs

此版本的foldl(例如,从左侧折叠,而不是从右侧折叠)是非严格的,这可能导致大量内存累积。最好使用foldl'中的严格变体Data.List

fillRec (x : xs) = foldl' fill x xs

答案 1 :(得分:0)

我将假设您已经定义了fill :: [Int] -> [Int] -> [Int]。如果是这样,使用fold很容易解决这个问题。明确地说,你可以做类似

的事情
fillAll :: [[Int]] -> [Int]
fillAll [] = []
fillAll (x:xs) = go x xs
    where
        go first [] = first
        go first (second:rest) = go (fill first second) rest

或者您可以使用其中一个内置fold s:

fillAll [] = []
fillAll (x:xs) = foldl fill x xs

但正如Impredicative指出的那样,使用Data.List中的foldl'可以获得更好的性能