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

发布于 2024-12-12 17:54:27 字数 354 浏览 1 评论 0原文

我有一个非常简单的 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

雪落纷纷 2024-12-19 17:54:27

您必须告诉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 视为使用 == while equal (或 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:

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

(Edit to address the question from the comments): As an alternative to equal, you could use string= in this example. This predicate is (in a way) less generic than equal and it might (could, probably, possibly, eventually...) thus be faster. A real benefit might be, that string= can tell you, if you pass a wrong value:

(equal 1 "foo")

happily yields nil, whereas

(string= 1 "foo")

gives a type-error condition. Note, though, that

(string= "FOO" :FOO)

is 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 of eql as using == while equal (or string=, etc.) calling the equals(Object) method. Though eql does some type introspection (as opposed to eq, 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 (and eql for non-numeric types) is more like the is operator, whereas equal is more like == which calls __eq__.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文