Лисп: Добавить соответствующие элементы списка списков - PullRequest
0 голосов
/ 01 октября 2018

Допустим, у меня есть список:

((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 голосов
/ 01 октября 2018

Другим вариантом является циклический просмотр списка списков:

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

Во время первой итерации первый список копируется.Полученный список затем используется в последовательных итерациях для хранения соответствующих сумм.В конце итерации возвращается этот список результатов.

0 голосов
/ 02 октября 2018

Наивным решением будет

(apply #'mapcar #'+ list)

Однако, как уже указывалось, например, здесь от stackoverflow и здесь от LispWorks , call-arguments-limit из (в худшем случае) 50 аргументов применяются к функциям, вызываемым 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)
0 голосов
/ 01 октября 2018

Один вариант - (apply #'mapcar #'+ list).Mapcar будет использовать столько списков, сколько вы дадите, и остановится, когда достигнет конца самого короткого списка.

...