2012-03-21 12 views
13

Ora questo funziona bene:Elisp: come eliminare un elemento da un elenco di associazione con stringa chiave

(setq al '((a . "1") (b . "2"))) 
(assq-delete-all 'a al) 

Ma sto usando stringhe come chiavi nel mio app:

(setq al '(("a" . "foo") ("b" . "bar"))) 

E questo non riesce a fare nulla:

(assq-delete-all "a" al) 

Penso che sia perché l'istanza dell'oggetto stringa è diversa

012 (?)

Quindi, come devo eliminare un elemento con una chiave stringa da un elenco di associazioni? O dovrei rinunciare e usare i simboli come chiavi e convertirli in stringhe quando necessario?

+1

A proposito, è necessario assegnare il risultato di "assq-delete-all' alla variabile anche se si tratta di un'operazione distruttiva:' (setq al (assq-delete-all 'a al)) '. Cosa succede se l'elenco diventa vuoto? Il 'al' deve assumere il valore nil: come accadrà? O cosa succede se elimini il primo elemento, il vantaggio principale a cui inizialmente punta al?'al' deve essere aggiornato per saltare alla seconda cella. – Kaz

risposta

11

Se sai che ci può essere solo una singola voce corrispondente nella lista, è anche possibile utilizzare il seguente modulo:

(setq al (delq (assoc <string> al) al) 

Si noti che il setq (che mancava dal codice di esempio) è molto importante per "cancellare" le operazioni sugli elenchi, altrimenti l'operazione fallisce quando l'elemento eliminato risulta essere il primo della lista.

13

Il q in assq significa tradizionalmente eq l'uguaglianza viene utilizzata per gli oggetti.

In altre parole, assq è un eq aromatizzato assoc.

Le stringhe non seguono l'uguaglianza eq. Due stringhe che sono sequenze di caratteri equivalenti potrebbero non essere eq. Lo assoc in Emacs Lisp usa l'uguaglianza equal che funziona con le stringhe.

Quindi quello che ti serve è un assoc-delete-all per l'elenco di associazioni basato su equal, ma tale funzione non esiste.

Tutto quello che posso trovare quando cerco assoc-delete-all è questa discussione mailing list: http://lists.gnu.org/archive/html/emacs-devel/2005-07/msg00169.html

rotolare il proprio. È abbastanza banale: fai marcia indietro nell'elenco e raccogli tutte le voci in una nuova lista il cui car non corrisponde alla chiave data sotto equal.

Una cosa utile da considerare potrebbe essere la libreria di compatibilità Common Lisp. http://www.gnu.org/software/emacs/manual/html_node/cl/index.html

Ci sono alcune funzioni utili lì, come remove*, con cui è possibile eliminare da un elenco con una funzione di predicato personalizzata per testare gli elementi. Con questo si può fare qualcosa di simile:

;; remove "a" from al, using equal as the test, applied to the car of each element 
(setq al (remove* "a" al :test 'equal :key 'car)) 

La variante distruttivo è delete*.

Problemi correlati