Emacs 在elisp中剥离字符串列表中的重复元素

Emacs 在elisp中剥离字符串列表中的重复元素,emacs,elisp,Emacs,Elisp,给出一个列表,例如 (list "foo" "bar" nil "moo" "bar" "moo" nil "affe") 我如何在删除重复字符串的情况下构建一个新列表,以及剥离nils,即 (list "foo" "bar" "moo" "affe") 需要保留元素的顺序-不能删除字符串的第一次出现 我在这里处理的列表很短,因此没有必要使用哈希表之类的东西来进行唯一性检查,尽管这样做肯定不会有什么坏处。但是,使用cl功能不是一个可行的选择。现在开始: (defun strip-duplic

给出一个列表,例如

(list "foo" "bar" nil "moo" "bar" "moo" nil "affe")
我如何在删除重复字符串的情况下构建一个新列表,以及剥离
nil
s,即

(list "foo" "bar" "moo" "affe")
需要保留元素的顺序-不能删除字符串的第一次出现

我在这里处理的列表很短,因此没有必要使用哈希表之类的东西来进行唯一性检查,尽管这样做肯定不会有什么坏处。但是,使用
cl
功能不是一个可行的选择。

现在开始:

(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)))
特别是,包含许多列表操作函数


是的,我知道你说过你不想使用
cl
。但我仍然认为这是一种正确的方法,可以帮助其他可能阅读本文的人

(为什么
cl
对您来说不可行?它与Emacs一起发布已经有大约20年了,不算过去版本中功能较少的版本。)

尝试以下方法:

如果您使用library,您只需要:

(-distinct (-non-nil '(1 1 nil 2 2 nil 3)) ; => (1 2 3)
dash.el
是由Magnar Sveen编写的,它是一个伟大的列表操作库,具有许多用于各种任务的函数。如果您编写了大量的Elisp代码,我建议您安装它。函数删除列表中的重复元素,删除
nil
元素。虽然上面的代码已经足够了,但下面我描述了一种替代方法,所以可以忽略本文的其余部分

-版本2.9中添加了非nil
,因此如果出于某种原因必须使用早期版本,另一种方法是使用内置函数,该函数只返回给定的值:
(标识1);=>1
。其思想是
-keep
只保留谓词返回true的元素(Lisp术语中的“non-nil”)
identity
显然只对非零的值返回非零:

(-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
,以测试元素是否重复


否则默认函数测试不会检查字符串是否相等。

这很好地解决了这个问题。我现在已经了解了
会员
。还有一个类似的函数允许指定比较函数吗?不,我不知道。不过,编写起来会非常简单。还有
memq
memql
。在重新创建已有实现的通用模式(在本例中为
delete dup
)之前,先阅读文档.如果你好奇的话,你可以比较一下你的实现:我一直在为Gnus做一些小补丁,在它的提交日志中,我经常看到一些变化,用一个非cl等价物替换cl中的某些东西。我不太清楚确切的原因是什么,但很可能是因为支持奇怪的Emacs风格或版本,或者除非真的有必要,否则尽量避免加载
cl
包。@rafl我相信对
cl
的限制是从RMS保持Emacs lisp小型化的愿望开始的。看看最近讨论这一点的帖子:@Trey:哦,我明白了。为了使Emacs的核心保持小型,需要每个包重新实现它们自己的基本数据结构和功能。好吧,如果你决定Emacs的核心将完全包含你所使用的特性,那么它是有效的。其他人都得到了重复的努力和膨胀…更加优雅和直接。有时我真的希望有类似于名称空间的东西将相关函数分组在一起,或者可能有一个更一致的命名方案,允许通过猜测它的名称来查找特定的东西:-/分组(通过命名约定或名称空间)很难,因为分组的方法总是很多。Emacs并不努力做到这一点,而是提供了类似于
apropos
的功能。但这也不理想。我们可能应该更加努力,尽管现在纠正大多数违法者有点晚了。
(-distinct (-keep 'identity '(1 1 nil 2 2 nil 3)) ; => (1 2 3)
(delete-duplicates '("~/.emacs.d" "~/.emacs.d") :test #'string-equal) ;; '("~/emacs.d")