假设我有一个列表:
((1 2 3) (8 4 7) (41 79 30) (0 8 5))
我想这样做:
(1+8+41+0 2+4+79+8 3+7+30+5) = (50 93 45)
我找到了一个丑陋的解决方案:
(defun nested+ (lst)
(let ((acc nil))
(dotimes (i (length (first lst)))
(push (apply #'+ (mapcar #'(lambda (a) (nth i a)) lst)) acc))
(reverse acc)))
这似乎可以达到我的目的,但是我猜它很慢而且很软。正确的方法是什么?
答案 0 :(得分:7)
一个选项是(apply #'mapcar #'+ list)
。 Mapcar将消耗您提供的尽可能多的列表,并在到达最短列表的末尾时停止。
答案 1 :(得分:5)
天真的解决方案是
(apply #'mapcar #'+ list)
但是,正如已经指出的here by stackoverflow和here by LispWorks,(在最坏的情况下)50个参数中的call-arguments-limit
适用于apply
调用的函数。建议使用reduce
。
因此,我建议:
(defun sum-all (lists)
(reduce #'(lambda (l1 l2) (mapcar #'+ l1 l2)) lists))
事实上
(sum-all '((1 2 3) (8 4 7) (41 79 30) (0 8 5)))
;; (50 93 45)
答案 2 :(得分:1)
另一种选择是遍历列表列表:
(defun sum-all (lists)
(loop
for list in lists
for result = (copy-list list) then (map-into result #'+ result list)
finally (return result)))
在第一次迭代期间,将复制第一个列表。然后,在连续的迭代中使用结果列表来保存相应的总和。在迭代结束时,将返回结果列表。