如何使用map和reduce计算数字列表的平均值。
理想情况下,我想在列表中调用reduce并获得平均值。您可以选择首先映射和过滤该列表。
骨架LISP尝试:
(defun average (list)
(reduce ... list))
骨架JS尝试:
function average (array) {
return array.reduce(function() {
..
}, 0);
}
如果您使用某种语言发布实际代码的答案,请解释一下,好像我是该语言的初学者(我可能会这样)。
我想避免
的简单回答function average (array) {
return sum(array) / array.length;
}
这在末尾使用除法而不是reduce语句。我认为这是“作弊”。
[[修改]]
解决了我自己的问题。如果有人使用来自LISP或Haskell的语法糖有一个优雅的解决方案,我会感兴趣。
答案 0 :(得分:3)
正如@abesto所说,它需要一个迭代算法。
Let counter be 0
For each [value, index] in list
let sum be (counter * index) + value
let counter be sum / (index + 1)
return counter
javascript实现将是
var average = function(list) {
// returns counter
return list.reduce(function(memo, val, key) {
// memo is counter
// memo * key + val is sum. sum / index is counter, counter is returned
return ((memo * key) + val) / (key + 1)
// let counter be 0
}, 0);
}
答案 1 :(得分:1)
以下是常见的lisp版本:
(defun running-avg (r v)
(let* ((avg (car r))
(weight (cdr r))
(new-weight (1+ weight)))
(cons (/ (+ (* avg weight) v) new-weight) new-weight)))
(car (reduce 'running-avg '(3 6 5 7 9) :initial-value '(0 . 0)))
;; evaluates to 6
跟踪运行平均值和重量,并将新平均值计算为((previous average * weight) + new value)
。
答案 2 :(得分:1)
使用map和reduce
计算数字列表的平均值
不需要map
。只需展开生成列表,然后折叠即可将其缩小为平均值:
mean n m = uncurry (/) . foldr g (0, 0) . unfoldr f $ n
where
f b | b > m = Nothing
| otherwise = Just (b, b+1)
g x (s,n) = (s+x, n+1)
有效的实施
此结构(fold . unfold
)允许进行融合优化。一个特别有效的实现将融合展开(列表生成)与折叠(列表缩减)融合。在Haskell中,GHC通过流融合将两个阶段(展开== enumFromN
)和折叠结合起来:
import Data.Vector.Unboxed
data Pair = Pair !Int !Double
mean :: Vector Double -> Double
mean xs = s / fromIntegral n
where
Pair n s = foldl' k (Pair 0 0) xs
k (Pair n s) x = Pair (n+1) (s+x)
main = print (mean $ enumFromN 1 (10^7))
编译器将两个函数的组合转换为递归循环:
main_loop a d e n =
case ># a 0 of
False -> (# I# n, D# e #);
True -> main_loop (-# a 1) (+## d 1.0) (+## e d) (+# n 1)
减少到程序集中的goto
(编译器的C后端):
Main_mainzuzdszdwfoldlMzqzuloop_info:
leaq 32(%r12), %rax
cmpq %rax, 144(%r13)
movq %r12, %rdx
movq %rax, %r12
jb .L198
testq %r14, %r14
jle .L202
.L199:
movapd %xmm5, %xmm0
leaq -1(%r14), %r14
movsd .LC0(%rip), %xmm5
addq $1, %rsi
addsd %xmm0, %xmm6
movq %rdx, %r12
addsd %xmm0, %xmm5
jmp Main_mainzuzdszdwfoldlMzqzuloop_info
更高效,但LLVM会产生更多令人困惑的实现(大约快2倍)。
答案 3 :(得分:0)
Haskell中允许组合方法折叠的方法的描述: http://conal.net/blog/posts/another-lovely-example-of-type-class-morphisms/
答案 4 :(得分:0)
在Mathematica中
mean[l_List]:=
Fold[{First@#1+1,(#2 +#1[[2]](First@#1-1))/First@#1}&,{1,1},l][[2]]
In[23]:= mean[{a,b,c}]
Out[23]= 1/3 (a+b+c)