Elisp:如何使用字符串键从关联列表中删除元素

aur*_*amo 16 lisp emacs elisp

现在这很好用:

(setq al '((a . "1") (b . "2")))
(assq-delete-all 'a al)
Run Code Online (Sandbox Code Playgroud)

但我在我的应用程序中使用字符串作为键:

(setq al '(("a" . "foo") ("b" . "bar")))
Run Code Online (Sandbox Code Playgroud)

这没有做任何事情:

(assq-delete-all "a" al)
Run Code Online (Sandbox Code Playgroud)

我认为那是因为字符串对象实例不同(?)

那么我应该如何从关联列表中删除带有字符串键的元素呢?或者我应该放弃并使用符号作为键,并在需要时将它们转换为字符串?

Kaz*_*Kaz 17

qassq传统上是指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))
Run Code Online (Sandbox Code Playgroud)

破坏性的变种是delete*.


Ste*_*fan 16

如果您知道列表中只能有一个匹配的条目,您还可以使用以下格式:

(setq al (delq (assoc <string> al) al)
Run Code Online (Sandbox Code Playgroud)

请注意,setq(示例代码中缺少的)对于列表上的"删除"操作非常重要,否则当删除的元素恰好是列表中的第一个时,操作将失败.


phi*_*ils 6

Emacs 27+ 包括assoc-delete-all哪些适用于字符串键,也可以与任意测试函数一起使用。

(assoc-delete-all KEY ALIST &optional TEST)

Delete from ALIST all elements whose car is KEY.
Compare keys with TEST.  Defaults to ‘equal’.
Return the modified alist.
Elements of ALIST that are not conses are ignored.
Run Code Online (Sandbox Code Playgroud)

例如:

(setf ALIST (assoc-delete-all KEY ALIST))
Run Code Online (Sandbox Code Playgroud)

在早期版本的 Emacs 中,cl-delete提供了一个替代方案:

(setf ALIST (cl-delete KEY ALIST :key #'car :test #'equal))
Run Code Online (Sandbox Code Playgroud)

这相当于从 ALIST 中删除项目,其中car列表项目的equalKEY 。

nb Kaz 的回答已经提到了后一个选项,但使用了旧(require 'cl)delete*and名称remove*,而您现在(为了支持 Emacs 24+)使用cl-deleteor cl-remove(自动加载)。