Lisp:添加列表列表中的各个元素

时间:2018-10-01 14:45:05

标签: nested lisp common-lisp

假设我有一个列表:

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

这似乎可以达到我的目的,但是我猜它很慢而且很软。正确的方法是什么?

3 个答案:

答案 0 :(得分:7)

一个选项是(apply #'mapcar #'+ list)。 Mapcar将消耗您提供的尽可能多的列表,并在到达最短列表的末尾时停止。

答案 1 :(得分:5)

天真的解决方案是

(apply #'mapcar #'+ list)

但是,正如已经指出的here by stackoverflowhere 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)))

在第一次迭代期间,将复制第一个列表。然后,在连续的迭代中使用结果列表来保存相应的总和。在迭代结束时,将返回结果列表。