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!