I have an alist whose keys are strings, and I need to set the value for one of its keys. If the key is not present, I need to add it. So for example,
(alist-set "a" "bb" '(("a" . "b") ("c" . "d"))) => '(("a" . "bb") ("c" . "d"))
(alist-set "a" "bb" '(("c" . "d"))) => '(("a" . "bb") ("c" . "d"))
Introducing duplicate entries is not acceptable. Mutating the original alist is allowed.
Here are some incorrect solutions:
Using
alist-get
:(setf (alist-get key alist) val)
This is incorrect because
alist-get
compares keys usingeq
, but string keys must be compared usingequal
. I could implement a new version of thesetf
accessor foralist-get
that usesequal
, but the original implementation ingv.el
is 26 lines of code. That is a lot of boilerplate for this simple operation.Using
setcdr
withassoc
:(setcdr (assoc key alist) val) (setf (cdr (assoc key alist)) val)
This is incorrect because it fails when the key is not present in the alist to begin with.
Use the fact that earlier entries in an alist shadow later ones:
(push (cons key val) alist)
This is incorrect because it introduces a duplicate entry for
key
in the alist.
Here are some questions whose answers do not answer this question:
alist-get
to accept an optionalTEST
parameter, which provides the comparison predicate to use. Alists with string keys are common. Seems like an oversight thatalist-get
hard-codeseq
.M-x report-emacs-bug RET
.