tags:

views:

52

answers:

2

I'm searching for a way to "pop" an element from an association list, in other words a "destructive" assoc:

(setq alist '((a . 1) (b . 2))
(assoc-pop 'a alist) ;; -> (a . 1)
;; alist -> ((b . 2))

Are there any function in the elisp harness? What's the most elegant way to obtain a symilar functionality? (not sure about that this sort of "side effect" is a good practice, even if it is possible!)

+1  A: 

assq-delete-all is close to what you want. It looks up elements by object identity (eq), not by value equality (equal). It removes all matching elements, not just the first. It returns the modified list. You can adapt the code of this function to do what you want. (But if you were going to call assoc-pop in a loop, and all your keys are symbols, assq-delete-all does all you need.)

Note that "a" and 'a are completely different objects: the first is a string, the second is a symbol. So your second line should have been (assoc-pop 'a alist).

But in fact, the call (assoc-pop 'a alist) can't work (unless assoc-pop is a macro), because it is incapable of removing the first element in a list. You can make a function that takes a symbol as argument and modifies the list that is the value of the symbol, following the model of add-to-list. You would call it as (assoc-pop 'a 'alist).

Gilles
Thank you also for the point about the symbols, I'm new to lisp and I haven't yet grasped the symbol/list/other_things stuff.I'm correcting the mistake!
pygabriel
+2  A: 

There is no such built-in operator that I am aware of, but I think that you can get this functionality quite quickly:

(defmacro assoc-pop (key alist)
  `(let ((result (assoc ,key ,alist)))
     (setq ,alist (delete result ,alist))
     result))
Svante