在 Clojure 中,什么时候应该在列表上使用向量,反过来呢?

我读到矢量不是序列,而列表是。我不知道用一个代替另一个的理由是什么。似乎矢量被使用的最多,但是有什么原因吗?

29618 次浏览

如果您已经做了很多 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)

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

再一次,似乎我已经回答了我自己的问题,变得不耐烦,并问它在 # clojure 在 Freenode。回答自己的问题是个好 stackoverflow.com

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

只是一个小小的附注:

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

sequences are more generic than either lists or vectors (or maps or sets).
Its unfortunate that the REPL prints lists and sequences the same because it really makes it look like lists are sequences even though they are different. the (seq ) function will make a sequence from a lot of different things including lists, and you can then feed that seq to any of the plethora of functions that do nifty things with seqs.

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);
}

列表是序列,尽管其他东西也是,并不是所有的序列都是列表。

何时使用矢量:

  • 索引访问性能——索引访问的成本为 ~ O (1) ,而列表的成本为 O (n)
  • 附加 -with conj 是 ~ O (1)
  • 方便的表示法——我发现对于文字列表来说,输入和读取[123]比读取’(123)更容易,因为两者都可行。

何时使用列表:

  • 当您希望按顺序访问它时(因为列表直接支持 seq 而不必分配新对象)
  • 前置-添加到带有 cons 或者最好是 conj 的列表的开头是 O (1)