37

While @Dan's answer is a perfectly fine solution, it is unnecessary. One of the reasons Emacs uses an alist here is that with an alist you can simply add a new element to the front of the list and it will shadow matches further down the list. (add-to-list 'auto-mode-alist '("\\.js\\'" . js2-mode))


33

Use setf to change the value in place: (setf (cdr (rassoc 'javascript-mode auto-mode-alist)) 'js2-mode) If you want to replace a value in the list, then setf is the generalized machinery you need to do so. For the more idiomatic way to deal with the auto-mode-alist, see @Drew's answer (and his explanation of shadowing).


22

It satisfies listp, so in that sense it is a list. listp just tests whether something is a cons or nil (aka ()), on the one hand, or something else, on the other hand. A proper list or true list (or a list that is not a dotted list or a circular list) is something that is listp and also has nil as its last cdr. That is, a list XS is proper if (cdr (last XS)...


19

The fastest way to actually change the cons cell is probably setcdr setcdr is a built-in function in `C source code'. (setcdr CELL NEWCDR) Set the cdr of CELL to be NEWCDR. Returns NEWCDR. It's worth noting that setf isn't available in older Emacsen, but setcdr is. *** Welcome to IELM *** Type (describe-mode) for help. ELISP> (setq tmp '((one . 1) (...


13

Here's an option which takes the exact syntax that you asked for but in a generalized way, and is quite simple to understand. The only difference is that the ALIST parameter needs to come first (you could adapt it to come last, if that's important to you). (defun assoc-recursive (alist &rest keys) "Recursively find KEYs in ALIST." (while keys (...


11

(cl-mapcar #'cons [apple orange] [5 10]) => ((apple . 5) (orange . 10)) (cl-mapcar #'list [apple orange] [5 10]) => ((apple 5) (orange 10)) Emacs's cl-mapcar takes as arguments a function of arity one or more and the same number of sequences as its arity. Common Lisp's mapcar is similar, but the only sequences it accepts are lists.


11

You can use cl-pairlis: (require 'cl-lib) (cl-pairlis '(apple orange) '(5 10)) ;; => ;; ((apple . 5) (orange . 10)) Also works for vectors: (cl-pairlis [apple orange] [5 10]) ;; => ;; ((apple . 5) (orange . 10)) (The cl library defines the shorter alias pairlis for cl-pairlis, but this is deprecated in newer Emacs versions.)


10

In Emacs-25, there's alist-get which you can use to get and set a key. E.g. you can do what you want with: (setf (alist-get 'width default-frame-alist) new-width)


6

Something like this? (require 'cl-lib) (cl-remove-if-not (apply-partially #'equal 'foo) '((foo . 5) (bar . 6) (foo . 7)) :key #'car) => ((foo . 5) (foo . 7)) (defun assoc-all (key list &optional testfn) "Like `assoc', but returns the list of all matching elements." (cl-remove-if-not (apply-partially (or ...


5

Another solution involving seq-filter: (seq-filter (lambda (elt) (equal (car elt) 'foo)) '((foo . 5) (bar . 6) (foo . 7)))


5

The OP asks for a solution which handles alists that have string keys. To handle that, see this question. If by chance you only need to handle alists with symbol keys, then as of Emacs 25 you can use: (setf (alist-get <key> <alist>) <value>) to replace a cdr. If you have access to Emacs 26, this technique does work with string keys, as ...


5

add-to-list accept a symbol as the first argument: (add-to-list 'function-key '(evil-next-line . 108)) If your variable is lexical, you will want to use push instead: (let ((foo ...)) (push ... foo)) NB. You might want to consider Hash Tables instead of alists for lookup (they correspond to dict in Python).


4

In addition to sds's suggestion of add-to-list, you can also use push, which doesn't require you to quote the variable: (push '(evil-next-line . 108) function-key)


4

First off, if you think that your alist has duplicate keys (which you call 'degenerate') and you want to remove them then you will have to call assq-delete-all or something like that. As to how to set the value without creating duplicate keys (since the simplest way to deal with an alist is to just cons on a new cons pair to the front) you will need to use ...


4

You most certainly want: (setq undo-tree-history-directory-alist '(("." . "~/.emacs.d/undo"))) The docstring of this variable speaks of an alist aka association list. These are a list of pairs, where a pair is a cons cell. The short-hand syntax for a cons cell is (foo . 1) whereas the short-hand syntax for returning a list as is would be '(...), both ...


4

According to the doc-string for assoc, it is used to: "Return non-nil if KEY is equal to the car of an element of LIST. The value is actually the first element of LIST whose car equals KEY." The manual contains a few examples: https://www.gnu.org/software/emacs/manual/html_node/elisp/Association-Lists.html The function plist-get appears to be ...


4

There isn't a built-in for that, hence why libraries like kv.el have been written. Your code can be significantly simplified though: (defun alist-keys (alist) (mapcar 'car alist))


3

Since Emacs version 26.1, alist-get accepts an optional argument testfn; when this argument is non-nil, then alist-get uses it to compare the keys instead of eq. Then you can do: (let ((alist (list (cons "a" "b") (cons "c" "d")))) (setf (alist-get "a" alist nil nil 'equal) "bb") alist) => (("a" . "bb") ("c" . "d")) Another way is to use the builtin ...


3

I came up with this solution, which does not require traversing the alist twice, and satisfies all of my other conditions. (defun alist-set (key val alist &optional symbol) "Set property KEY to VAL in ALIST. Return new alist. This creates the association if it is missing, and otherwise sets the cdr of the first matching association in the list. It ...


3

The issue is mostly caused by autoloads. In julia-mode.el you can see that (add-to-list 'auto-mode-alist '("\\.jl\\'" . julia-mode)) is marked as to be autoloaded. If you were to look at ~/.emacs.d/elpa/julia-mode-${version}/julia-mode-autoloads.el (which is automatically generated from julia-mode.el when you initially install the package), you would indeed ...


3

You've already received tips on what to use instead of assoc, but just to answer your original question: assoc expects a list of cons cells as input: (setq testvar '((:type "http") (:path "//pygments.org/docs") (:format bracket) (:raw-link "http://pygments.org/docs") (:application nil))) (assoc :path testvar) ==> (:path "//pygments....


3

Some things to consider wrt your code (in no special order): Why use a plist instead of an alist? Either choice is OK, but at least ask yourself the question. What final plist do you expect to get? Plists generally use symbols, not strings, as the keys. So if you have strings you will want to use intern to get symbols. If your input is a buffer of such ...


2

Here's a more generic solution: (defun assoc-multi-key (path nested-alist) "Find element in nested alist by path." (if (equal nested-alist nil) (error "cannot lookup in empty list")) (let ((key (car path)) (remainder (cdr path))) (if (equal remainder nil) (assoc key nested-alist) (assoc-multi-key remainder (...


2

I think you were on the right track but your regular expression does not escape the final ) character, like so: "\\.\\(txt\\|markdown\\|md\\)\\(\\'\\|\\.\\)" As a general tip, you can test out Emacs regular expressions using regexp-builder. Put some example text in a scratch buffer, say: foo.md foo.md.lastweek foo.md.orig foo.mdnomatch Then do M-x regexp-...


2

If you know you won't use javascript-mode ever again let auto-mode-alist untouched and add to your init.el (defalias 'javascript-mode 'js2-mode "Some handy explanation goes here.")


2

Recursion for the win. (defun json-filter-paths (json paths) (mapcar (lambda (elt) (if (consp elt) (cons (car elt) (json-filter-paths (cdr (assoc (car elt) json)) (cdr elt))) (cons elt (cdr (assoc elt json))))) paths)) (json-filter-paths'((owner (login . "octocat") (avatar . "blah")...


1

Cute. Take a look at the beginning of the alist again: ((1 . [((id . 2) (attribute . salutation)… It looks like the key is a number, so I tried that (assoc 1 tester) nil It doesn't have any quotes, but maybe a string? (assoc "1" tester) nil Nope. It's actually a symbol whose name is the single digit 1: (assoc '\1 tester) (\1 . [((id . 2)… When I ...


1

Here is one solution. It doesn't give exactly the order you specified, but they are sorted by folder. #+BEGIN_SRC emacs-lisp (sort '((("id" . "005") ("folder" . "EVENTS") ("misc" . "apples") ("foo" . "1")) (("id" . "123") ("folder" . "CONTACTS") ("misc" . "oranges") ("foo" . "3")) (("id" . "975") ("folder" . "UNDATED") ("misc" . "figs") ("foo" . "7")...


1

The Emacs Lisp Manual gives a good explanation. Here's a brief summary: If you are associating info with something that is already a Lisp function or variable, plists are faster because they're usually smaller and tied directly to the symbol. But the plist of a symbol is a global namespace, so different packages might conflict. If you are trying to have ...


1

There is an old alist.el library from the Emacs vs XEmacs days - someone added it to their .emacs folder so you can browse it - https://github.com/baron/emacs/blob/master/.emacs.d/el-get/apel/alist.el. It would let you say (set-alist 'default-frame-alist 'width 80) It's not namespaced to 'alist-' though, and not orthogonal - eg it has (put-alist KEY VALUE ...


Only top voted, non community-wiki answers of a minimum length are eligible