ChatGPT解决这个技术问题 Extra ChatGPT

在 Clojure 中,何时应该在列表上使用向量,反之亦然?

我读到向量不是序列,但列表是。我不确定使用其中一个的理由是什么。似乎向量使用得最多,但这是有原因的吗?


R
Rayne

再一次,似乎我已经通过不耐烦并在 Freenode 上的#clojure 中提出问题来回答我自己的问题。 Stackoverflow.com 鼓励您回答自己的问题:D

我与 Rich Hickey 进行了快速讨论,这里是它的要点。

[12:21] <Raynes>    Vectors aren't seqs, right?
[12:21] <rhickey>   Raynes: no, but they are sequential
[12:21] <rhickey>   ,(sequential? [1 2 3])
[12:21] <clojurebot>    true
[12:22] <Raynes>    When would you want to use a list over a vector?
[12:22] <rhickey>   when generating code, when generating back-to-front
[12:23] <rhickey>   not too often in Clojure

当您在 freenode 上时,来到黑暗面并加入 #stackoverflow! :-P
我实际上曾经在那里闲置。我切换了 IRC 客户端,但从未想过将 #stackoverflow 添加到我的自动加入列表中。
我是一个 Lisp 新手,但我想知道向量、映射和集合是否以某种方式打破了所有代码都可以与数据互换的想法?或者这只是使 Clojure 成为实用 Lisp 的原因之一? (或者,你能评估一个向量吗?)
这是完全无用的聊天片段。 “生成代码”“从后到前生成”-> 准确的意思??我真的很难回答这个问题,因为在我的书中懒惰 + 声明式风格 = 更好的性能,但是在 Clojure 中到处都建议使用向量,这让我完全困惑。
@JimmyHoffa 我理解它的方式:“生成代码”=“在宏内部”(因为大部分代码都是函数调用,因此是列表); “从后到前生成” = “通过前置构建序列”。
C
Chris Jester-Young

如果您从事过大量 Java 编程,并且熟悉 Java 集合框架,请考虑 LinkedList 之类的列表和 ArrayList 之类的向量。所以你几乎可以用同样的方式选择容器。

进一步说明:如果您打算将项目单独添加到序列的前面或后面,链表比向量好得多,因为项目不需要每次都打乱。但是,如果您想经常(即随机访问)获取特定元素(不在列表的前面或后面),您将需要使用 vector.

顺便说一句,向量可以很容易地变成序列。

user=> (def v (vector 1 2 3))
#'user/v
user=> v
[1 2 3]
user=> (seq v)
(1 2 3)
user=> (rseq v)
(3 2 1)

向量不是序列,但它们是连续的。 (来源:Rich 本人在 freenode 上的#clojure 上。)另外,我根本不了解 Java,但 Rich 确实回答了我的问题。
我将编辑我的帖子说,可以通过 seq 函数将向量制成序列。 :-)
选择你的答案是因为它确实回答了这个问题,而且我真的不喜欢选择我自己的答案作为正确答案。似乎不对。谢谢。 :)
在添加首尾的情况下,双端队列优于链表。 LL非常糟糕:P
@boxed 如果不自己有效地重新实现 ArrayDeque,您将无法在向量或 ArrayList 之上实现双端队列。
S
Svante

向量具有 O(1) 随机访问时间,但它们必须预先分配。列表可以动态扩展,但访问随机元素是 O(n)。


从技术上讲,链表有 O(1) 的访问时间……如果你只访问前面或后面的元素。 :-P 但是,向量确实有 O(1) 随机访问。 :-)
(上面描述的“链表”指的是双向链表。单链表只能 O(1) 访问前面的元素。:-P)
作为一个刚刚进入 Clojure 的人,这是一个比其他两个投票更多的更好的答案。另外两个告诉我没有用。
@ChrisJester-Young 单链表可以支持 O(1) 对后面的访问,如果它存储对后面元素 like that 的引用。
T
Thumbnail

何时使用向量:

索引访问性能 - 索引访问的成本约为 O(1),而列表的成本约为 O(n)

附加 - 与 conj 是 ~O(1)

方便的表示法 - 我发现在任何一个都可以工作的情况下,对于文字列表,输入和阅读 [1 2 3] 都比 '(1 2 3) 更容易。

何时使用列表:

当您想将其作为序列访问时(因为列表直接支持 seq 而无需分配新对象)

前置 - 使用 cons 或最好是 conj 添加到列表的开头是 O(1)


即使在两端添加/删除列表也是一个非常糟糕的选择。双端队列要好得多(在 CPU 中,尤其是在内存中)。试试github.com/pjstadig/deque-clojure
回复:~O(1),对于本成本说明可能对他们有帮助的人 - stackoverflow.com/questions/200384/constant-amortized-time
A
Arthur Ulfeldt

只是一个快速的旁注:

"I read that Vectors are not seqs, but Lists are."

序列比列表或向量(或映射或集合)更通用。不幸的是,REPL 打印的列表和序列相同,因为它确实使列表看起来像序列,即使它们不同。 (seq) 函数将从包括列表在内的许多不同事物中创建一个序列,然后您可以将该序列提供给任何使用 seq 完成漂亮事情的函数。

user> (class (list 1 2 3))
clojure.lang.PersistentList

user> (class (seq (list 1 2 3)))
clojure.lang.PersistentList

user> (class (seq [1 2 3]))
clojure.lang.PersistentVector$ChunkedSeq

Sec 有一个快捷方式,如果它已经是一个 seq,则返回它的参数:

user> (let [alist (list 1 2 3)] (identical? alist (seq alist)))
true
user> (identical? (list 1 2 3) (seq (list 1 2 3)))
false

static public ISeq seq(Object coll){
        if(coll instanceof ASeq)
                return (ASeq) coll;
        else if(coll instanceof LazySeq)
                return ((LazySeq) coll).seq();
        else
                return seqFrom(coll);
}

列表是序列,尽管其他事物也是如此,并且并非所有序列都是列表。


我不是要挑一个小点,它只是一个机会指出一些有用的东西。许多人已经知道这一点:)
您不是说 class 而不是 class? 吗?
不确定您的示例是否在 clojure 更新后发生了变化(我想我在 1.5 上),但是您的两个示例都为我返回了 clojure.lang.PersistentList。我假设您打算写 class 而不是 class?
我确实做到了!我会解决的
还是有点糊涂;因为 class 为您提到的这两个表达式返回相同的 PersistentList,这意味着序列和列表确实是完全相同的东西?