1

Let's say I have a list:

((1 2 3) (8 4 7) (41 79 30) (0 8 5))

I want to do this:

(1+8+41+0 2+4+79+8 3+7+30+5) = (50 93 45)

I've found an ugly solution:

(defun nested+ (lst)
  (let ((acc nil))
    (dotimes (i (length (first lst)))
      (push (apply #'+ (mapcar #'(lambda (a) (nth i a)) lst)) acc))
    (reverse acc)))

It seems to work for my purposes, but I guess it is slow and un-lispy. What's the proper way?

coredump
  • 37,664
  • 5
  • 43
  • 77
Kotlopou
  • 415
  • 3
  • 13

3 Answers3

8

One option is (apply #'mapcar #'+ list). Mapcar will consume as many lists as you give it and stop when it reaches the end of the shortest list.

Xach
  • 11,774
  • 37
  • 38
  • 1
    This is a neat answer but can fail mysteriously for long lists (I am sure Xach knows this, but the person asking may not). –  Oct 01 '18 at 19:03
  • you are talking about `call-arguments-limit` of functions - the number of maximum arguments a function can take, which is implementation-dependent and should be at least 50. In my sbcl I see it has the value of 536870911 and clisp 4096, so quite many ... – Gwang-Jin Kim Oct 01 '18 at 22:48
  • 2
    @Gwang-JinKim: in ABCL - Common Lisp on the JVM - it's just 50. Not that many. – Rainer Joswig Oct 02 '18 at 07:56
  • 2
    @Gwang-JinKim: even in CLISP a 4096-element list is not very long! –  Oct 03 '18 at 07:06
7

The naive solution would be

(apply #'mapcar #'+ list)

However, as already pointed out e.g. here by stackoverflow and here by LispWorks, the call-arguments-limit of (in the worst case) 50 arguments applies to functions called by apply. And reduce is suggested instead.

Thus, I suggest:

(defun sum-all (lists)
  (reduce #'(lambda (l1 l2) (mapcar #'+ l1 l2)) lists))

And indeed

(sum-all '((1 2 3) (8 4 7) (41 79 30) (0 8 5)))
;; (50 93 45)
Gwang-Jin Kim
  • 9,303
  • 17
  • 30
1

Another option is to loop over your list of lists:

(defun sum-all (lists)
  (loop
    for list in lists
    for result = (copy-list list) then (map-into result #'+ result list)
    finally (return result)))

During the first iteration, the first list is copied. The resulting list is then used in successive iterations to hold the respective sums. At the end of the iteration, that result list is returned.

coredump
  • 37,664
  • 5
  • 43
  • 77