使用 mapcar 计算欧式距离并应用
Compute euclidean distance with mapcar and apply
我正在尝试创建一个函数,使用 apply 和 mapcar 来计算它。
在使用第一个 mapcar 获取列表中 p-q 的所有差异后,我被卡住了。如何对列表中的所有元素进行平方并求和?
(defun euclidean-distance-map (p q)
;; get a list of differences of p - q
(mapcar #'- p q))
高阶函数
如果您确实需要坚持使用 HOF (reduce
& mapcar
),那么这里有几个选项:
(defun euclidean-distance-map (p q)
(let ((d (mapcar #'- p q))) ; get a list of differences of p & q
(sqrt (reduce #'+ (mapcar #'* d d)))))
(defun euclidean-distance-map (p q)
(sqrt (reduce #'+ (mapcar (lambda (x) (* x x)) (mapcar #'- p q)))))
(defun euclidean-distance-map (p q)
(sqrt (reduce #'+ (mapcar (lambda (x y)
(let ((d (- x y)))
(* d d)))
p q))))
apply
对比 reduce
使用 apply
instead of reduce
is a bad idea (both because of call-arguments-limit
和风格),但现在开始:
(defun euclidean-distance-map (p q)
(let ((d (mapcar #'- p q))) ; get a list of differences of p & q
(sqrt (apply #'+ (mapcar #'* d d)))))
(defun euclidean-distance-map (p q)
(sqrt (apply #'+ (mapcar (lambda (x) (* x x)) (mapcar #'- p q)))))
(defun euclidean-distance-map (p q)
(sqrt (apply #'+ (mapcar (lambda (x y)
(let ((d (- x y)))
(* d d)))
p q))))
内存
没有众所周知的 "sufficiently smart compiler",mapcar
分配的存储空间会立即被丢弃。
不过,这不一定是现代分代 GC 的问题。
迭代
注意使用loop
的迭代版本同样清晰:
(defun euclidean-distance-map (p q)
(sqrt (loop for x in p
and y in q
for d = (- x y)
sum (* d d))))
Lisp 是一种多范式语言,您不必强迫自己进入specific 框架。
coredump- 实际上回答了它,但让我们详细说明一下。问题可以拆分为以下tasks/steps(从最外层到最内层):
- 计算平方根,就是我们知道的:
(sqrt .)
- 要得到
.
,我们需要求和平方差。这里 apply
将完成工作。我们想要 (+ a1 a2 a3 ...)
,问题是我们不知道要添加多少项。假设这些项目可以放入列表中,可以做到(apply #'+ .)
。所以,到目前为止,我们有 (sqrt (apply #'+ .))
.
- 现在我们需要对差进行平方并将结果放入列表中。这可以通过
mapcar
完成:(mapcar (lambda (x) (* x x)) .)
.
- 最后,这个差异需要来自
(mapcar #'- u v)
。
总体而言,
(defun euclidian-distance (u v)
(sqrt (apply #'+ (mapcar (lambda (x) (* x x)) (mapcar #'- u v)))))
> (euclidian-distance '(1 4 3) '(1 1 -1))
> 5.0
这是一个使用高阶函数并且不为差异分配列表的变体:
(defun euclidian-distance (u v)
(let ((sum 0.0))
(mapc (lambda (x y)
(let ((d (- x y)))
(incf sum (* d d))))
u
v)
(sqrt sum)))
我正在尝试创建一个函数,使用 apply 和 mapcar 来计算它。
在使用第一个 mapcar 获取列表中 p-q 的所有差异后,我被卡住了。如何对列表中的所有元素进行平方并求和?
(defun euclidean-distance-map (p q)
;; get a list of differences of p - q
(mapcar #'- p q))
高阶函数
如果您确实需要坚持使用 HOF (reduce
& mapcar
),那么这里有几个选项:
(defun euclidean-distance-map (p q)
(let ((d (mapcar #'- p q))) ; get a list of differences of p & q
(sqrt (reduce #'+ (mapcar #'* d d)))))
(defun euclidean-distance-map (p q)
(sqrt (reduce #'+ (mapcar (lambda (x) (* x x)) (mapcar #'- p q)))))
(defun euclidean-distance-map (p q)
(sqrt (reduce #'+ (mapcar (lambda (x y)
(let ((d (- x y)))
(* d d)))
p q))))
apply
对比 reduce
使用 apply
instead of reduce
is a bad idea (both because of call-arguments-limit
和风格),但现在开始:
(defun euclidean-distance-map (p q)
(let ((d (mapcar #'- p q))) ; get a list of differences of p & q
(sqrt (apply #'+ (mapcar #'* d d)))))
(defun euclidean-distance-map (p q)
(sqrt (apply #'+ (mapcar (lambda (x) (* x x)) (mapcar #'- p q)))))
(defun euclidean-distance-map (p q)
(sqrt (apply #'+ (mapcar (lambda (x y)
(let ((d (- x y)))
(* d d)))
p q))))
内存
没有众所周知的 "sufficiently smart compiler",mapcar
分配的存储空间会立即被丢弃。
不过,这不一定是现代分代 GC 的问题。
迭代
注意使用loop
的迭代版本同样清晰:
(defun euclidean-distance-map (p q)
(sqrt (loop for x in p
and y in q
for d = (- x y)
sum (* d d))))
Lisp 是一种多范式语言,您不必强迫自己进入specific 框架。
coredump- 实际上回答了它,但让我们详细说明一下。问题可以拆分为以下tasks/steps(从最外层到最内层):
- 计算平方根,就是我们知道的:
(sqrt .)
- 要得到
.
,我们需要求和平方差。这里apply
将完成工作。我们想要(+ a1 a2 a3 ...)
,问题是我们不知道要添加多少项。假设这些项目可以放入列表中,可以做到(apply #'+ .)
。所以,到目前为止,我们有(sqrt (apply #'+ .))
. - 现在我们需要对差进行平方并将结果放入列表中。这可以通过
mapcar
完成:(mapcar (lambda (x) (* x x)) .)
. - 最后,这个差异需要来自
(mapcar #'- u v)
。
总体而言,
(defun euclidian-distance (u v)
(sqrt (apply #'+ (mapcar (lambda (x) (* x x)) (mapcar #'- u v)))))
> (euclidian-distance '(1 4 3) '(1 1 -1))
> 5.0
这是一个使用高阶函数并且不为差异分配列表的变体:
(defun euclidian-distance (u v)
(let ((sum 0.0))
(mapc (lambda (x y)
(let ((d (- x y)))
(incf sum (* d d))))
u
v)
(sqrt sum)))