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.