Извлечение элемента из списка ассоциаций в lisp (elisp)

Я ищу способ «вытолкнуть» элемент из списка ассоциаций, другими словами, «деструктивный» ассоциативный элемент:

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

Есть ли какая-нибудь функция в обвязке elisp? Какой самый элегантный способ получить аналогичную функциональность? (не уверен, что такого рода «побочный эффект» является хорошей практикой, даже если это возможно!)


person pygabriel    schedule 13.08.2010    source источник


Ответы (2)


Насколько я знаю, такого встроенного оператора нет, но я думаю, что вы можете получить этот функционал довольно быстро:

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

assq-delete-all близко к тому, что вы хотите. Он ищет элементы по идентификатору объекта (eq), а не по равенству значений (equal). Он удаляет все соответствующие элементы, а не только первый. Он возвращает измененный список. Вы можете адаптировать код этой функции, чтобы делать то, что вы хотите. (Но если вы собираетесь вызывать assoc-pop в цикле, а все ваши ключи являются символами, assq-delete-all сделает все, что вам нужно.)

Обратите внимание, что "a" и 'a — совершенно разные объекты: первый — строка, второй — символ. Итак, ваша вторая строка должна была быть (assoc-pop 'a alist).

Но на самом деле вызов (assoc-pop 'a alist) не может работать (если только assoc-pop не является макросом), потому что он не может удалить первый элемент в списке. Вы можете создать функцию, которая принимает символ в качестве аргумента и изменяет список, являющийся значением символа, следуя модели add-to-list. Вы бы назвали это (assoc-pop 'a 'alist).

person Gilles 'SO- stop being evil'    schedule 13.08.2010
comment
Спасибо также за замечание о символах, я новичок в lisp и еще не разобрался с символами/списками/другими вещами. Я исправляю ошибку! - person pygabriel; 13.08.2010