Merge plists in Elisp
Say that you have two property lists in Elisp (list :a 1 :b 3)
and
(list :a 2)
: you may need to merge them to obtain (list :a 2 :b
3)
. This operator exists in Clojure, but I didn't seem to find it nor
in seq.el, nor dash.el nor in other Emacs' built-in libraries.
I also needed the operation to do a "deeper" merge:
(me-merge (list :andrea-favourites (list "food")) (list :andrea-favourites (list "books"))) ; => (:andrea-favourites ("food" "books"))
And this is what I got to:
(defun me-keys (plist) "Return keys of PLIST." (--filter (and (symbolp it) (s-starts-with-p ":" (symbol-name it))) plist)) ; (me-keys '(:a 1 :b 2)) ; => (:a :b) (defun me-merge (join-when-you-can? &rest plists) "Merge keys of PLISTS when possible. If JOIN-WHEN-YOU-CAN? is true, if keys contain lists, we append their results instead of replacing." (--reduce (-reduce-from (lambda (acc1 key) (let ((a (plist-get acc key)) (b (plist-get it key))) (if (and join-when-you-can? (listp a) (listp b)) (append acc1 (list key (-union a b))) (append acc1 (list key b))))) nil (-union (me-keys it) (me-keys acc))) plists)) ;(me-merge t '(:a ("1") :b "2") '(:a ("3") :b "3")) ; => (:a ("1" "3") :b "3") ;(me-merge nil '(:a "1" :b "2") '(:a "3" :b "3")) ; => (:a "3" :b "3")
Happy merging!