使用 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(从最外层到最内层):

  1. 计算平方根,就是我们知道的:(sqrt .)
  2. 要得到.,我们需要求和平方差。这里 apply 将完成工作。我们想要 (+ a1 a2 a3 ...),问题是我们不知道要添加多少项。假设这些项目可以放入列表中,可以做到(apply #'+ .)。所以,到目前为止,我们有 (sqrt (apply #'+ .)).
  3. 现在我们需要对差进行平方并将结果放入列表中。这可以通过 mapcar 完成:(mapcar (lambda (x) (* x x)) .).
  4. 最后,这个差异需要来自(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)))