编写一个函数,返回列表的累加和。例如,running [1,2,3,5]是 [1,3,6,11]。我编写了下面的函数,只能返回列表中所有值的最终和。那么如何将它们逐个分开?
sumlist' xx=aux xx 0
where aux [] a=a
aux (x:xs) a=aux xs (a+x)
编写一个函数,返回列表的累加和。例如,running [1,2,3,5]是 [1,3,6,11]。我编写了下面的函数,只能返回列表中所有值的最终和。那么如何将它们逐个分开?
sumlist' xx=aux xx 0
where aux [] a=a
aux (x:xs) a=aux xs (a+x)
我认为你想要结合scanl1
和(+)
,做类似下面这样的事情:
scanl1 (+) *your list here*
scanl1将给定函数应用于列表,并将每个中间值报告到返回的列表中。
例如,为了在伪代码中写出它,
scanl1 (+) [1,2,3]
将输出一个类似以下列表:
[a, b, c] where { a = 1, b = a+2, c = b+3 }
换句话说,
[1, 3, 6]
Learn You A Haskell提供了很多有关Haskell中扫描、折叠等内容的精彩例子和描述。
希望这可以帮到你。
a+x
并使用空列表作为基本情况,来调整您的函数以生成一个列表:sumlist' xx = aux xx 0
where aux [] a = []
aux (x:xs) a = (a+x) : aux xs (a+x)
然而,用fold或scan表达这种情况更符合Haskell的习惯。
尽管scanl1显然是“规范”的解决方案,但看看如何使用foldl来解决问题仍然具有启示意义:
sumList xs = tail.reverse $ foldl acc [0] xs where
acc (y:ys) x = (x+y):y:ys
或者点分风格:
sumList = tail.reverse.foldl acc [0] where
acc (y:ys) x = (x+y):y:ys
这里有一个丑陋的暴力方法:
sumList xs = reverse $ acc $ reverse xs where
acc [] = []
acc (x:xs) = (x + sum xs) : acc xs
有一个可爱但不太高效的解决方案,使用inits
函数:
sumList xs = tail $ map sum $ inits xs
再次提到无参量函数:
sumList = tail.map sum.inits
reverse
?在正向方向上,sumList = (\
snd` []) . foldl (\(a, k) x -> (a+x, k . (a+x:))) (0, id)` 可以正常工作。 - ephemientscanl1 (+)
,但它会在返回之前强制处理整个输入列表的结构,所以无法用于无限列表。 (是啊,十年过去了... :)) - Will Nessrsum xs = map (\(a,b)->a+b) (zip (0:(rsum xs)) xs)
我认为它甚至相当高效。
map (uncurry f) $ zip xs ys == zipWith f xs ys
,因此该函数为 rsum xs = zipWith (+) (0:(rsum xs)) xs
,但它没有像应该的那样重复使用结果(因此是二次的),像下面这样就是线性的:rsum xs = rs where rs = zipWith (+) (0:rs) xs
,或者 scanl1 (+) xs
也是线性的。 - Will Ness我不确定这是否是规范的,但在我看来它很漂亮 :)
sumlist' [] = []
sumlist' (x:xs) = x : [x + y | y <- sumlist' xs]
sumList:: Num a => [a] -> [a]
sumList xs = foldlr (\x l r -> (x + l):r) 0 [] xs
定义foldr使其在列表中是非严格的并不太困难。请注意,它必须有两个初始值--一个从左边开始(0),一个从右边结束([]):
foldlr :: (a -> b -> [b] -> [b]) -> b -> [b] -> [a] -> [b]
foldlr f l r xs =
let result = foldr (\(l', x) r' -> f x l' r') r (zip (l:result) xs) in
result
aux (x:xs) a = a `seq` (a+x) : aux xs (a+x)
。请仅返回已翻译的文本。 - Will Ness