从列表中删除重复的字符串
我有一个非常简单的 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宿醉。
I have a dead simple Common Lisp question: what is the idiomatic way of removing duplicates from a list of strings?
remove-duplicates
works as I'd expect for numbers, but not for strings:
* (remove-duplicates '(1 2 2 3))
(1 2 3)
* (remove-duplicates '("one" "two" "two" "three"))
("one" "two" "two" "three")
I'm guessing there's some sense in which the strings aren't equal, most likely because although "foo" and "foo" are apparently identical, they're actually pointers to different structures in memory. I think my expectation here may just be a C hangover.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您必须告诉remove-duplicates 它应该如何比较这些值。默认情况下,它使用
eql
,这对于字符串来说是不够的。传递:test
函数,如下所示:(编辑以解决评论中的问题):作为
equal
的替代方案,您可以使用string=
在此示例中。这个谓词(在某种程度上)不如equal
那么通用,并且它可能(可能、可能、可能、最终......)因此更快。真正的好处可能是,如果您传递了错误的值,string=
可以告诉您:愉快地产生
nil
,而给出
type-error
> 条件。但请注意,这是完全明确定义的(
string=
及其朋友是根据“字符串指示符”而不是字符串定义的),因此类型安全在这里只能进行到此为止。另一方面,标准 eql 谓词几乎从来都不是比较字符串的正确方法。如果您熟悉 Java 语言,请将
eql
视为使用==
whileequal
(或string=
等)调用equals(Object)
方法。虽然 eql 进行了一些类型自省(与 eq 不同,后者没有),但对于大多数(非数字)lisp 类型,eql 会沸腾如果您想根据值实际包含的内容而不是仅仅根据它们在内存中的位置来区分值,那么像指针比较之类的东西是不够的。对于更 Pythonic 的人来说,
eq
(对于非数字类型为eql
)更像是is
运算符,而equal< /code> 更像是调用
__eq__
的==
。You have to tell remove-duplicates how it should compare the values. By default, it uses
eql
, which is not sufficient for strings. Pass the:test
function as in:(Edit to address the question from the comments): As an alternative to
equal
, you could usestring=
in this example. This predicate is (in a way) less generic thanequal
and it might (could, probably, possibly, eventually...) thus be faster. A real benefit might be, thatstring=
can tell you, if you pass a wrong value:happily yields
nil
, whereasgives a
type-error
condition. Note, though, thatis perfectly well defined (
string=
and its friend are defined in terms of "string designators" not strings), so type safety would go only so far here.The standard
eql
predicate, on the other hand, is almost never the right way to compare strings. If you are familiar with the Java language, think ofeql
as using==
whileequal
(orstring=
, etc.) calling theequals(Object)
method. Thougheql
does some type introspection (as opposed toeq
, which does not), for most (non-numeric) lisp types,eql
boils down to something like a pointer comparison, which is not sufficient, if you want to discriminate values based on what they actually contain, and not merely on where in memory they are located.For the more Pythonic inclined,
eq
(andeql
for non-numeric types) is more like theis
operator, whereasequal
is more like==
which calls__eq__
.