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

Dun*_*yne 5 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")
Run Code Online (Sandbox Code Playgroud)

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

Dir*_*irk 17

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

(remove-duplicates your-sequence :test #'equal). 
Run Code Online (Sandbox Code Playgroud)

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

(equal 1 "foo")
Run Code Online (Sandbox Code Playgroud)

愉快地收益nil,而

(string= 1 "foo")
Run Code Online (Sandbox Code Playgroud)

给出一个type-error条件.但请注意

(string= "FOO" :FOO)
Run Code Online (Sandbox Code Playgroud)

完全定义良好(string=其朋友的定义是"字符串指示符"而不是字符串),所以类型安全只会到这里.

eql另一方面,标准谓词几乎不是比较字符串的正确方法.如果您熟悉Java语言,请考虑eql使用==while equal(或string=等)调用equals(Object)方法.虽然对于大多数(非数字)lisp类型,eql某些类型的内省(相反eq,但没有),可eql归结为像指针比较这样的东西,这是不够的,如果你想根据它们实际的区别来区分值包含,而不仅仅是它们所在的记忆位置.

对于更多Pythonic倾斜,eq(和eql非数字类型)更像是is 运算符,而equal更像==是调用__eq__.