在Clojure中添加一个向量的惯用方法是什么?

预先列表很容易:

user=> (conj '(:bar :baz) :foo) (:foo :bar :baz) 

追加向量很容易:

 user=> (conj [:bar :baz] :foo) [:bar :baz :foo] 

我如何(习惯性地)在向量上添加一个向量? 这不起作用,因为它返回一个seq,而不是一个vector:

 user=> (cons :foo [:bar :baz]) (:foo :bar :baz) 

这是丑陋的(IMVHO):

 user=> (apply vector (cons :foo [:bar :baz])) [:foo :bar :baz] 

注:我基本上只是想要一个数据结构,我可以追加和prepend。 追加到大列表应该有一个很大的性能损失,所以我想vector..

向量不是为预先devise的。 你只有O(n)预先:

 user=> (into [:foo] [:bar :baz]) [:foo :bar :baz] 

你想要的是最有可能的一个手指树 。

我知道这个问题是旧的,但没有人说差异列表的任何事情,因为你说你真的只是想要的东西,你可以追加和prepend,这听起来像差异列表可能会帮助你。 它们在Clojure中似乎并不stream行,但是它们非常容易实现,并且比手指树简单得多,所以我刚才做了一个很小的差异列表库(甚至testing它)。 这些连接在O(1)时间(前置或附加)。 将差异列表转换回列表应该花费你O(n),如果你做了很多连接,这是一个很好的折衷。 如果你没有进行大量的连接,那么就坚持列表吧? 🙂

这个小图书馆的function如下:

dl:差异列表实际上是将自己的内容与参数连接起来并返回结果列表的函数。 每当你产生一个差异列表,你正在创build一个像数据结构一样的小函数。

dlempty:由于差异列表只是将其内容连接到参数,空的差异列表与身份函数是相同的。

undl:因为list有什么不同,你可以通过调用nil来将差异列表转换成普通列表,所以这个函数并不是真正需要的。 这只是为了方便。

dlcons:将一个项目放在列表的前面 – 不是完全必要的,但是consing是一个普通的操作,它只是一个单行(就像这里所有的函数一样)。

dlappend:连接两个差异列表。 我认为它的定义是最有趣的 – 检查出来! 🙂

现在,这里是一个小型的库 – 5个单行函数,给你一个O(1)的append / prepend数据结构。 不错,呃? 啊,Lambda微积分的美丽…

 (defn dl "Return a difference list for a list" [l] (fn [x] (concat lx))) ; Return an empty difference list (def dlempty identity) (defn undl "Return a list for a difference list (just call the difference list with nil)" [aDl] (aDl nil)) (defn dlcons "Cons an item onto a difference list" [item aDl] (fn [x] (cons item (aDl x)))) (defn dlappend "Append two difference lists" [dl1 dl2] (fn [x] (dl1 (dl2 x)))) 

你可以看到它在这个行动:

 (undl (dlappend (dl '(1 2 3)) (dl '(4 5 6)))) 

它返回:

 (1 2 3 4 5 6) 

这也返回相同的东西:

 ((dl '(1 2 3)) '(4 5 6)) 

玩得开心!

更新

以下是一些可能更难理解的定义,但我认为更好:

 (defn dl [& elements] (fn [x] (concat elements x))) (defn dl-un [l] (l nil)) (defn dl-concat [& lists] (fn [x] ((apply comp lists) x))) 

这让你可以这样说:

 (dl-un (dl-concat (dl 1) (dl 2 3) (dl) (dl 4))) 

哪会回来

 (1 2 3 4) 

如用户optevo在手指树答案下的注释中所述,可以使用实现RRB树的clojure / core.rrb-vector库:

RRB-Trees基于Clojure的PersistentVectors,增加了对数时间连接和切片。 ClojureScript支持相同的API,除了没有vector-of函数。

我决定把这个post作为一个单独的答案,因为我认为这个图书馆是值得的。 它支持ClojureScript,它由MichałMarczyk维护,他在Clojure社区中为其实现各种数据结构的工作而着称。

我build议使用图珀洛图书馆内置的便利function。 例如:

 (append [1 2] 3 ) ;=> [1 2 3 ] (append [1 2] 3 4) ;=> [1 2 3 4] (prepend 3 [2 1]) ;=> [ 3 2 1] (prepend 4 3 [2 1]) ;=> [4 3 2 1] 

相比之下,与原始的Clojure很容易犯一个错误:

 ; Add to the end (concat [1 2] 3) ;=> IllegalArgumentException (cons [1 2] 3) ;=> IllegalArgumentException (conj [1 2] 3) ;=> [1 2 3] (conj [1 2] 3 4) ;=> [1 2 3 4] ; Add to the beginning (conj 1 [2 3] ) ;=> ClassCastException (concat 1 [2 3] ) ;=> IllegalArgumentException (cons 1 [2 3] ) ;=> (1 2 3) (cons 1 2 [3 4] ) ;=> ArityException