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

我读了vector不是序列,但列表是。 我不确定使用一个的理由是什么。 看起来vector是最常用的,但这是有原因的吗?

再一次,似乎我已经不耐烦地回答了我自己的问题,并且在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 

如果你已经完成了Java编程,并熟悉Java收集框架,那么可以考虑像LinkedList这样的列表,以及像ArrayList这样的向量。 所以你几乎可以用同样的方法select容器。

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

顺便说一下,向量可以很容易地变成seqs。

 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)个随机访问时间,但必须预先分配。 列表可以dynamic扩展,但访问一个随机元素是O(n)。

何时使用vector:

  • 索引访问性能 – 对于列表,您获得索引访问的O(1)成本与O(n)成本
  • 附加 – 连接是〜O(1)
  • 方便的表示法 – 我发现在任何一种情况下,对于字面表来说,键入和读取[1 2 3]比'(1 2 3)'更容易。

何时使用列表:

  • 当你想作为一个序列访问它(因为列表直接支持seq而不必分配新的对象)
  • 预先考虑 – 用cons或者连接词加到列表的开头是O(1)

只是一个快速的一面说明:

  “我读了vector不是seqs,而是列表。” 

序列比列表或向量(或地图或集合)更通用。
不幸的是,REPL打印列表和序列相同,因为它真的使它看起来像列表是序列,即使它们是不同的。 (seq)函数将从许多不同的东西(包括列表)中创build一个序列,然后你可以将这个seq提供给seqs中很多function的任何一个函数。

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

列表是序列,尽pipe其他事情也是如此,并不是所有的序列都是列表。