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

问题描述 投票:0回答:5

我读到向量不是序列,但列表是。我不确定使用其中一种而不是另一种的理由是什么。看起来向量用得最多,但是有什么原因吗?

list vector clojure sequences
5个回答
128
投票

我与 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

100
投票

如果您经常进行 Java 编程,并且熟悉 Java 集合框架,请考虑像

LinkedList
这样的列表和像
ArrayList
这样的向量。所以你几乎可以用同样的方式选择容器。

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

顺便说一下,向量可以很容易地转换成序列。

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)

55
投票

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


32
投票

何时使用向量:

  • 索引访问性能 - 索引访问的成本约为 O(1),而列表的成本为 O(n)
  • 附加 - 与 conj 是 ~O(1)
  • 方便的符号 - 我发现在任何一种都可以工作的情况下,对于文字列表来说,输入和阅读 [1 2 3] 比 '(1 2 3) 更容易。

何时使用列表:

  • 当你想将其作为序列访问时(因为列表直接支持 seq 而无需分配新对象)
  • Prepending - 添加到列表的开头 cons 或最好是 conj 是 O(1)

15
投票

只是一个简短的旁注:

“我读到向量不是序列,但列表是。” 

序列比列表或向量(或映射或集合)更通用。
不幸的是,REPL 打印列表和序列是相同的,因为它确实让列表看起来像是序列,尽管它们是不同的。 (seq ) 函数将从包括列表在内的许多不同内容创建一个序列,然后您可以将该 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);
}

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

© www.soinside.com 2019 - 2024. All rights reserved.