假设有一个列表,如下所示:
(list "foo" "bar" nil "moo" "bar" "moo" nil "affe")
我该如何构建一个新的列表,将重复的字符串移除并去除nil
,即:
(list "foo" "bar" "moo" "affe")
需要保留元素的顺序 - 不能删除字符串的第一次出现。
我处理的列表比较短,因此不需要使用哈希表进行唯一性检查,尽管这样做肯定也没有坏处。但是,使用 cl
功能不是可行的选择。
请在Emacs Lisp参考手册的"列表"部分中尝试"集合和列表":
(delq nil (delete-dups (list "foo" "bar" nil "moo" "bar" "moo" nil "affe")))
Common Lisp package包含许多列表操作函数,特别是remove-duplicates
。
(require 'cl)
(remove-duplicates (list "foo" "bar" nil "moo" "bar" "moo" nil "affe")
:test (lambda (x y) (or (null y) (equal x y)))
:from-end t)
是的,我知道你说你不想使用cl
。但我仍然提到这个作为正确的方法,为其他可能阅读此线程的人提供参考。
(为什么cl
对你来说不可行呢?它已经随Emacs一起发布了大约20年了,不包括过去功能较少的版本。)
cl
包,除非真正必要。 - raflcl
的限制始于RMS希望保持emacs-lisp的小巧。请查看最近讨论此观点的线程:http://lists.gnu.org/archive/html/emacs-devel/2010-09/msg01278.html - Trey Jacksondash.el
库,那就足够了:(-distinct (-non-nil '(1 1 nil 2 2 nil 3)) ; => (1 2 3)
dash.el
由Magnar Sveen编写,是一个非常棒的列表操作库,具有许多用于各种任务的函数。如果你经常编写Emacs Lisp代码,我建议你安装它。函数-distinct
从列表中删除重复元素,-non-nil
删除nil
元素。虽然上面的代码已经足够,但下面我描述了一种替代方法,所以可以忽略本帖子的其余部分。
-non-nil
在版本2.9中添加,因此如果出于某种原因您必须使用较早的版本,则实现相同效果的另一种方法是使用内置的-keep
和identity
函数,该函数只返回其所接收到的参数:(identity 1) ; => 1
。思路是-keep
仅保留断言返回true(Lisp术语中的“非nil”)的元素。显然,identity
仅对不是nil的值返回非nil:
(-distinct (-keep 'identity '(1 1 nil 2 2 nil 3)) ; => (1 2 3)
这是一个简短的例子:
(delete-duplicates '("~/.emacs.d" "~/.emacs.d") :test #'string-equal) ;; '("~/emacs.d")
:test
关键字选择函数string-equal
来测试元素是否重复。
否则,默认的函数测试不会检查字符串相等性。
这是你想要的:
(defun strip-duplicates (list)
(let ((new-list nil))
(while list
(when (and (car list) (not (member (car list) new-list)))
(setq new-list (cons (car list) new-list)))
(setq list (cdr list)))
(nreverse new-list)))
member
。是否还有类似的函数可以指定比较函数? - raflmemq
和memql
。 - philsdelete-dups
)之前,阅读文档可以得到一个更好的答案。 - aculich
apropos
这样的东西。但这也不是理想的解决方案。我们可能应该更加努力,虽然现在修复大多数问题有点晚了。 - Stefan