我正在尝试获取一个返回单个列表标准偏差的函数,我的代码运行得很好,但我想学习如何使用map,apply和filter来应用此代码。到目前为止,我已经使用了普通函数的应用程序,但我无法在其余的代码中使用它们
(define (average li)
(/ (apply + li) (length li)))
(define (summation li avg)
(if (null? li)
0
(+
(* (- (car li) avg)
(- (car li) avg))
(summation (cdr li) avg))))
(define (sd li)
(sqrt
(/
(summation li (average li))
(- (length li) 1))))
我觉得地图可以在求和函数中使用,但它会犯一个大错误。
答案 0 :(得分:2)
您可以使用foldl
summation
(define (summation li avg)
(foldl (lambda (x acc)
(+ acc
(expt (- x avg)
2)))
0
li))
虽然这里提供的这些程序看似简单,但您应该考虑其实施的后果。例如,我确定您可以编写自己的length
函数
(define (length li)
(if (null? li)
0
(+ 1 (length (cdr li)))))
您使用(apply + li)
来计算输入列表的总和,但我确信您已经意识到这是我们简单的递归解决方案的明智替代
(define (sum li)
(if (null? li)
0
(+ (car li)
(sum (cdr li)))))
鉴于sum
和length
,我们实施了average
(define (average li)
(/ (sum li)
(length li)))
你在这看到问题吗? sum
和length
都遍历输入列表。然后我们继续写sd
...
(define (sd li)
(sqrt (/ (summation li
(average li))
(- (length li)
1))))
你看到问题是如何恶化的吗?我们知道average
已逐步完成输入列表li
两次,summation
逐步完成再次,并注意到另一个 em>致电length
- 我们已经li
4 次重复,sd
可以返回结果
让我们回顾一下。看average
,如果我们可以通过某种方式将li
和的元素同时计算在内,那会不会很好?好吧,我们可以!
(define (average li (return /))
(if (null? li)
(return 0 0)
(average (cdr li)
(lambda (sum count)
(return (+ sum (car li))
(+ count 1))))))
(average '(1)) ;; 1
(average '(1 2)) ;; 1 1/2
(average '(1 2 3)) ;; 2
(average '()) ;; Error: division by zero
使用此技术,您几乎可以执行任何复杂的转换。使用这种风格写sd
留给读者练习。