用mapcar计算欧氏距离并应用

时间:2016-02-10 19:05:23

标签: lisp common-lisp

我正在尝试创建一个使用apply和mapcar来计算它的函数。

在使用第一张mapcar获取列表中p-q的所有差异后,我陷入困境。如何平方列表中的所有元素并将它们相加?

enter image description here

(defun euclidean-distance-map (p q)
  ;; get a list of differences of p - q
  (mapcar #'- p q))

3 个答案:

答案 0 :(得分:7)

高阶函数

如果你真的需要坚持使用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 vs reduce

使用apply代替reduce是一个错误的想法(因为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))))

内存

如果没有众所周知的“足够智能的编译器”,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框架。

答案 1 :(得分:2)

coredump-实际上回答了它,但让我们详细说明一下。问题可以分为以下任务/步骤(从最外层到最内层):

  1. 计算平方根,我们知道:(sqrt .)
  2. 要获得.,我们需要总结平方差异。这里apply将完成工作。我们想要(+ a1 a2 a3 ...),问题是我们不知道要添加多少项。假设这些项目可以放入列表中,可以(apply #'+ .)。所以,到目前为止,我们已经(sqrt (apply #'+ .))
  3. 现在我们需要对差异进行平方并将结果放入列表中。这可以通过mapcar(mapcar (lambda (x) (* x x)) .)
  4. 来完成
  5. 最后,这些差异需要来自(mapcar #'- u v)
  6. 总的来说,

    (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
    

答案 2 :(得分:1)

这是一个使用高阶函数的变体,并没有为差异分配列表:

(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)))