Alist

Umas lista associativa é uma lista de cons cells.

Este simples exemplo:

(defparameter *my-alist* (list (cons 'foo "foo")
                             (cons 'bar "bar")))
;; => ((FOO . "foo") (BAR . "bar"))

fica assim:

[o|o]---[o|/]
 |       |
 |      [o|o]---"bar"
 |       |
 |      BAR
 |
[o|o]---"foo"
 |
FOO

Nós podemos construir uma alist de acordo com sua representação:

(setf *my-alist* '((:foo . "foo")
                 (:bar . "bar")))

O construtor pairlis associa uma lista de chaves a uma lista de valores:

(pairlis '(:foo :bar)
         '("foo" "bar"))
;; => ((:BAR . "bar") (:FOO . "foo"))

Para pegar uma chave, nós temos assoc (use :test 'equal quando suas chaves forem strings, como sempre). Ela retorna a toda a cons cell, então você pode usar cdr ou second para obter o valor, ou ainda melhor, assoc-value list key de Alexandria.

(alexandria:assoc-value *my-alist* :foo)
;; it actually returns 2 values
;; "foo"
;; (:FOO . "FOO")

Existem assoc-if, e rassoc para obter uma cons cell a partir do seu valor.

Para adicionar uma chave, nós fazemos push para outra cons cell:

(push (cons 'team "team") *my-alist*)
;; => ((TEAM . "team") (FOO . "foo") (BAR . "bar"))

Podemos usar pop e outras funções que operam sobre listas, como remove:

(remove :team *my-alist*)
;; => ((:TEAM . "team") (FOO . "foo") (BAR . "bar")) ;; didn't remove anything
(remove :team *my-alist* :key 'car)
;; => ((FOO . "foo") (BAR . "bar")) ;; returns a copy

Remover apenas um elemento com :count:

(push (cons 'bar "bar2") *my-alist*)
;; => ((BAR . "bar2") (TEAM . "team") (FOO . "foo") (BAR . "bar")) ;; twice the 'bar key
(remove 'bar *my-alist* :key 'car :count 1)
;; => ((TEAM . "team") (FOO . "foo") (BAR . "bar"))
;; because otherwise:
(remove 'bar *my-alist* :key 'car)
;; => ((TEAM . "team") (FOO . "foo")) ;; no more 'bar

Na biblioteca Alexandria veja mais funções como remove-from-plist, alist-plist, ...