2011-10-29 45 views
5

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

remove-duplicates作品我期望的数字,而不是字符串:

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

(1 2 3) 

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

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

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

回答

17

你必须告诉remove-duplicates它应该如何比较值。默认情况下,它使用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归结为类似于指针比较的东西,但如果您想根据它们实际上包含的内容,而不仅仅是它们在内存中的位置。

对于更Python倾斜,eq(和eql用于非数字类型)是更像is操作者,而equal更像==它调用__eq__

+0

我会试图使用STRING =而不是EQUAL。 – Vatine

+1

为什么?有什么不同? – rivasket

+0

STRING =使用根据[HyperSpec](http://www.lispworks.com/documentation/HyperSpec/Body/f_chareq.htm#char-equal)的CHAR =比较字符“...如果所有字符都是如果两个字符在任何实现定义的属性中不同,那么它们不是char =“。我不确定使用实现定义的行为是一个更好的选择。 –

相关问题