我有一个面试问题,从那以后一直困扰着我。
我有一个函数,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]
答案 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'
可以获得更好的性能