Вопрос

There are two list like:

(setf l1 '((1 . 1) (2 . 2) (3 . 3)  (4 . 4) (5 . 5)))
(setf l2 '(2  22  4  44  6 66))    ;; this is a alist

I want to merge these two list to one like:

((1 . 1) (2 . 22) (3 . 3)  (4 . 44) (5 . 5)  (6 . 66))

I can use some Set function to do like intersection and set-difference.

But I want to implement that using map function without iterator function like do, loop , I have no idea how to do it.

Это было полезно?

Решение

With respect to the lists, this does not look like a merge but like an update: you want to update the data in l1 with the updates specified in l2.

(defun update (target updates)
  "Returns a copy of the alist TARGET where the values are updated according
to the plist UPDATES."
  (mapcar (lambda (assoc)
            (let ((update (getf updates (car assoc) :not-found)))
              (if (eq update :not-found)
                  assoc
                  (cons (car assoc) update))))
          target))

If updates gets bigger than a few tens of elements, you should first transform it to a data structure that better scales with respect to random lookups.

Другие советы

First you need to convert l2 to a bona fide alist:

(setq l3 (loop for (a b) on l2 by #'cddr collect (cons a b)))
==> ((2 . 22) (4 . 44) (6 . 66))

Next you can merge them:

(setq l4 (merge 'list l1 l3 #'< :key #'car))
==> ((1 . 1) (2 . 2) (2 . 22) (3 . 3) (4 . 4) (4 . 44) (5 . 5) (6 . 66))

Now you can remove the duplicates (BEWARE! unnecessary quadratic complexity!):

(setq l5 (delete-duplicates l4 :key #'car))
==> ((1 . 1) (2 . 22) (3 . 3) (4 . 44) (5 . 5) (6 . 66))
  1. I don't think you can do this with a simple map.
  2. The most efficient implementation will use a single hand-crafted loop, not system functions.
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top