reddit / emacs

A little function to merge plists in Elisp

AndreaSomePostfix · 2022-10-30 19:25
ak-coram · 2022-10-31 04:58
Here's my take on this: (defun merge-plists-with (f &rest plists) (labels ((plist-keys (plist) (cl-loop for k in plist by #'cddr collect k))) (cl-loop with keys = (delete-dups (cl-mapcan #'plist-keys plists)) for key in keys collect key collect (funcall f (cl-loop for plist in plists when (plist-member plist key) collect (getf plist key)))))) ;; take value from last plist containing key (merge-plists-with (lambda (values) (car (last values))) '(:a 1 :b 2) '(:a nil :c 4)) ;; => (:a nil :b 2 :c 4) ;; join lists when possible (merge-plists-with (lambda (values) (if (cl-every #'listp values) (apply #'append values) (car (last values)))) '(:a 1 :b 2 :d (1 2 3)) '(:a nil :c 4 :d (4 5 6))) ;; => (:a nil :b 2 :d (1 2 3 4 5 6) :c 4)
organic-bookworm · 2022-10-31 07:32
There are `map-merge` and `map-merge-with` functions in built-in `map.el` library. (require 'map) (require 'seq) (defun me-merge (join-when-you-can? &rest plists) (apply #'map-merge-with 'plist (lambda (a b) (if (and join-when-you-can? (listp a) (listp b)) (seq-union a b) b)) plists))
[deleted] · 2022-10-31 13:27
[deleted]
arthurno1 · 2022-10-31 13:50
(defun me-merge (join-when-you-can? &rest plists) (apply #'map-merge-with 'plist (lambda (a b) (if (and join-when-you-can? (listp a) (listp b)) (seq-union a b) b)) plists)) That is very nice. Just as a note and a bit further thought, that works nice for ordinary lists as sublists, but it will also try to merge plists and alists since they will test positive for listp. We can easily extend this to a recursive version and pass the type of sublists to merge and switch on the type: (defun me-merge (join &rest plists) (apply #'map-merge-with 'plist (lambda (a b) (if (and join (listp a) (listp b)) (cond ((eq join 'list) (seq-union a b)) ((eq join 'plist) (me-merge join a b))) b)) plists)) Example: (me-merge 'plist '(:a (:one "1") :b "2") '(:a (:one "3") :b "3")) (me-merge 'list '(:a 1 :b 2 :d (1 2 3)) '(:a nil :c 4 :d (4 5 6))) (me-merge nil '(:a 1 :b 2 :d (1 2 3)) '(:a nil :c 4 :d (4 5 6))) But then there might be lists with sublists of mixed types, how to deal with alists and other types etc. But in some cases it could be probably useful. By the way, I understand you have just answered the Ops problem statement, I just wanted to develop a bit more for the fun, I don't mean to critique your code :).
AndreaSomePostfix · 2022-11-01 22:51
Thanks for sharing an alternative solution!
AndreaSomePostfix · 2022-11-01 22:52
nice! I am going to explore map.el, thanks!
AndreaSomePostfix · 2022-11-01 22:52
interesting thanks a lot for developing this further :)