Elisp: удаление элемента из списка ассоциаций со строковым ключом
Теперь это работает отлично:
(setq al '((a . "1") (b . "2")))
(assq-delete-all 'a al)
Но я использую строки как ключи в своем приложении:
(setq al '(("a" . "foo") ("b" . "bar")))
И это ничего не может сделать:
(assq-delete-all "a" al)
Я думаю, что поскольку экземпляр строкового объекта отличается (?)
Итак, как я должен удалить элемент со строковым ключом из списка ассоциаций? Или я должен отказаться от использования символов в качестве ключей и преобразовать их в строки при необходимости?
Ответы
Ответ 1
Если вы знаете, что в вашем списке может быть только одна соответствующая запись, вы также можете использовать следующую форму:
(setq al (delq (assoc <string> al) al)
Обратите внимание, что setq
(который отсутствовал в вашем примере кода) очень важен для операций "delete" в списках, иначе операция завершится неудачно, когда удаленный элемент окажется первым в списке.
Ответ 2
q
assq
традиционно означает eq
для объектов используется равенство.
Другими словами, assq
является eq
ароматизированным assoc
.
Строки не соответствуют равенству eq
. Две строки, эквивалентные последовательностям символов, могут не быть eq
. assoc
в Emacs Lisp использует equal
равенство, которое работает со строками.
Итак, вам нужен assoc-delete-all
для вашего списка ассоциаций с equal
, но эта функция не существует.
Все, что я могу найти, когда я ищу assoc-delete-all
, это этот список рассылки:
http://lists.gnu.org/archive/html/emacs-devel/2005-07/msg00169.html
Сканируй свой собственный. Это довольно тривиально: вы маршируете по списку и собираете все эти записи в новый список, чей car
не соответствует указанному ключу в equal
.
Одна полезная вещь, на которую можно обратить внимание, - это библиотека совместимости Common Lisp. http://www.gnu.org/software/emacs/manual/html_node/cl/index.html
Здесь есть некоторые полезные функции, такие как remove*
, с помощью которых вы можете удалить из списка пользовательскую предикатную функцию для тестирования элементов. С этим вы можете сделать что-то вроде этого:
;; 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))
Деструктивный вариант delete*
.