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

时间:2012-03-21 20:34:41

标签: emacs lisp elisp

现在这很好用:

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

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

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

这没有做任何事情:

(assq-delete-all "a" al)

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

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

4 个答案:

答案 0 :(得分:17)

q中的assq传统上意味着eq相等用于对象。

换句话说,assqeq风味的assoc

字符串不遵循eq平等。两个等效字符序列的字符串可能不是eq。 Emacs Lisp中的assoc使用equal相等,它与字符串一起使用。

所以你需要的是基于assoc-delete-all的关联列表的equal,但该函数不存在。

我搜索assoc-delete-all时可以找到的是此邮件列表主题: http://lists.gnu.org/archive/html/emacs-devel/2005-07/msg00169.html

滚动你自己。这是相当简单的:您沿着列表前进,并将所有这些条目收集到carequal下的给定密钥不匹配的新列表中。

要看一个有用的东西可能是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*

答案 1 :(得分:16)

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

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

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

答案 2 :(得分:4)

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.

例如:

(setf ALIST (assoc-delete-all KEY ALIST))

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

(setf ALIST (cl-delete KEY ALIST :key #'car :test #'equal))

相当于说要从列表项的car到KEY的ALIST中删除项目。

n.b。 Kaz的答案已经提到了后一种选择,但是使用了equal(require 'cl)的旧delete*名称,而您现在(为了支持Emacs 24+)使用remove*cl-delete(已自动加载)。

答案 3 :(得分:2)

如果使用emacs 25或更高版本,则可以使用alist-get

(setf (alist-get "a" al t t 'equal) t)