从列表中删除重复的字符串

时间:2011-10-29 09:05:46

标签: common-lisp

我有一个简单的Common Lisp问题:从字符串列表中删除重复项的惯用方法是什么?

remove-duplicates正如我对数字所期望的那样,但不是字符串:

* (remove-duplicates '(1 2 2 3))

(1 2 3)

* (remove-duplicates '("one" "two" "two" "three"))

("one" "two" "two" "three")

我猜测有一些感觉,字符串不相等,很可能因为虽然“foo”和“foo”显然是相同的,但它们实际上是指向内存中不同结构的指针。我想我的期望可能只是一个C宿醉。

1 个答案:

答案 0 :(得分:17)

你必须告诉remove-duplicatelicates它应该如何比较这些值。默认情况下,它使用eql,这对于字符串来说是不够的。传递:test函数,如下所示:

(remove-duplicates your-sequence :test #'equal). 

(编辑以解决评论中的问题):作为equal的替代方案,您可以在此示例中使用string=。这个谓词(在某种程度上)不如equal那么通用,它可能(可能,可能,最终......)因此更快。如果传递错误的值,string=可以告诉您真正的好处:

(equal 1 "foo")

愉快地产生nil,而

(string= 1 "foo")

给出type-error条件。但请注意,

(string= "FOO" :FOO)

是完全明确定义的(string=,其朋友是根据“字符串指示符”而不是字符串来定义的,所以类型安全只会到目前为止。

另一方面,标准eql谓词几乎不是比较字符串的正确方法。如果您熟悉Java语言,请将eql视为使用==equal(或string=等)调用equals(Object)方法。虽然eql进行了某种类型的内省(与eq相反,但没有),对于大多数(非数字)lisp类型,eql归结为类似指针比较的内容,如果你想根据它们实际包含的内容来区分值,而不仅仅是它们在内存中的位置,那么这是不够的。

对于更多Pythonic倾向,eq(和eql非数字类型)更像is运算符,而equal更像{{1}调用==