给定向量列表的质心
Centroid given a list of vectors
我必须计算给定向量列表的平均向量,例如这个向量
'((2 3 56) (22 45 34) (21 2 23) (4 8 3) (4 4 1) (4 4 5))
简而言之,我必须找到给定列表列表的质心。
(defun vsum (x y)
(cond ((not (= (list-length x) (list-length y))) (error "dimension error!"))
((null (first x)) NIL)
(t (cons (+ (first x) (first y)) (vsum (rest x) (rest y))))))
我已经创建了这个简单的函数,但是我在以递归方式使用它(我更喜欢它反对循环)来完成我的任务时遇到了很大的麻烦。我也需要它与维度无关(例如,大多数大小为 2 或 3 的向量)。
在这种情况下不需要循环或递归,只需要原始泛函:
(defun centroid (list)
(when list
(let ((list-length (length list))
(dimension (length (first list))))
(unless (every (lambda (v) (= (length v) dimension)) (rest list))
(error "Dimension error!"))
(mapcar (lambda (x) (/ x list-length))
(reduce (lambda (x y) (mapcar #'+ x y)) list)))))
使用的公式是针对有限点集的公式(参见 Wikipedia)。
首先检查所有向量是否具有相同的维度(every
部分),然后与(reduce (lambda (x y) (mapcar #'+ x y)) list)
部分计算和,最后每个坐标是除以点数(mapcar
部分)。
I prefer it against the loop
但这没有任何意义。递归函数更难使用并且会导致堆栈溢出。
你的vsum
函数最好写成
(defun vsum (x y)
(assert (= (length x) (length y)) ; both lists of equal length
(x y) ; the lists, can be repaired
"Dimension error") ; the error message
(mapcar #'+ x y)) ; simple mapping
以上版本为
- 由于使用了 ASSERT
,在出错的情况下更适合交互使用
- 更短
- 更清晰
- 对于更大的输入列表
没有堆栈溢出问题
mapcar
表达式可以用loop
写成:
(loop for x1 in x and y1 in y
collect (+ x y))
这仍然比你的递归代码更清晰、更短。
我必须计算给定向量列表的平均向量,例如这个向量
'((2 3 56) (22 45 34) (21 2 23) (4 8 3) (4 4 1) (4 4 5))
简而言之,我必须找到给定列表列表的质心。
(defun vsum (x y)
(cond ((not (= (list-length x) (list-length y))) (error "dimension error!"))
((null (first x)) NIL)
(t (cons (+ (first x) (first y)) (vsum (rest x) (rest y))))))
我已经创建了这个简单的函数,但是我在以递归方式使用它(我更喜欢它反对循环)来完成我的任务时遇到了很大的麻烦。我也需要它与维度无关(例如,大多数大小为 2 或 3 的向量)。
在这种情况下不需要循环或递归,只需要原始泛函:
(defun centroid (list)
(when list
(let ((list-length (length list))
(dimension (length (first list))))
(unless (every (lambda (v) (= (length v) dimension)) (rest list))
(error "Dimension error!"))
(mapcar (lambda (x) (/ x list-length))
(reduce (lambda (x y) (mapcar #'+ x y)) list)))))
使用的公式是针对有限点集的公式(参见 Wikipedia)。
首先检查所有向量是否具有相同的维度(every
部分),然后与(reduce (lambda (x y) (mapcar #'+ x y)) list)
部分计算和,最后每个坐标是除以点数(mapcar
部分)。
I prefer it against the loop
但这没有任何意义。递归函数更难使用并且会导致堆栈溢出。
你的vsum
函数最好写成
(defun vsum (x y)
(assert (= (length x) (length y)) ; both lists of equal length
(x y) ; the lists, can be repaired
"Dimension error") ; the error message
(mapcar #'+ x y)) ; simple mapping
以上版本为
- 由于使用了 ASSERT ,在出错的情况下更适合交互使用
- 更短
- 更清晰
- 对于更大的输入列表 没有堆栈溢出问题
mapcar
表达式可以用loop
写成:
(loop for x1 in x and y1 in y
collect (+ x y))
这仍然比你的递归代码更清晰、更短。