在列表之前很容易:
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]
注意:我基本上只想要一个可以附加和前置的数据结构。附加到大型列表应该会有很大的性能损失,所以我想到了矢量..
答案 0 :(得分:70)
答案 1 :(得分:17)
我知道这个问题已经过时了,但没有人对差异说过什么 列表,因为你说你真的只想要一些你可以追加的东西 并且在前面,它听起来像差异列表可能会帮助你。 它们在Clojure中似乎并不受欢迎,但它们非常简单 实施并且比手指树复杂得多,所以我做了一个 微小的差异列表库,刚才(甚至测试过它)。这些 在O(1)时间内连接(前置或附加)。转换差异 列表返回列表应该花费你O(n),这是一个很好的权衡,如果 你做了很多连接。如果你没有做很多事情 连接,然后只是坚持列表,对吧? :)
以下是这个小型库中的函数:
dl:差异列表实际上是一个自己连接的函数 带有参数的内容并返回结果列表。每次 你产生一个差异列表,你正在创建一个小功能 就像数据结构一样。
dlempty:由于差异列表只是将其内容汇总到了 参数,空差异列表与身份相同 功能
undl:由于列表有什么不同,您可以转换一个 差异列表只是通过用nil调用它到正常列表,所以这个 功能不是真的需要;这只是为了方便。
dlcons:将一个项目汇总到列表的前面 - 不完全 必要的,但是进行是一个足够普遍的操作,它只是一个 单行(就像所有的功能一样)。
dlappend:汇总了两个差异列表。我认为它的定义是 最有趣的 - 看看吧! :)
现在,这是一个很小的库 - 5个单行函数,可以给你一个O(1) 追加/前置数据结构。不错,嗯?啊,Lambda的美丽 演算...
(defn dl
"Return a difference list for a list"
[l]
(fn [x] (concat l x)))
; 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)
答案 2 :(得分:2)
正如用户optevo在指纹树下的评论中所说,你可以使用实现RRB树的clojure/core.rrb-vector lib:
RRB-Trees构建在Clojure的PersistentVectors上,添加了对数时间连接和切片。除了缺少
vector-of
函数外,ClojureScript支持相同的API。
我决定将此作为单独的答案发布,因为我认为这个库值得这样做。它支持ClojureScript,它由Michał Marczyk维护,他在Clojure社区中因实现各种数据结构而闻名。
答案 3 :(得分:1)
我建议使用便利功能built into the Tupelo Library。例如:
(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
答案 4 :(得分:1)
如果您不担心使用准引号,则此解决方案实际上非常优雅(对于“优雅”的某些定义):
> `[~:foo ~@[:bar :baz]]
[:foo :bar :baz]
我实际上有时在真实代码中使用此代码,因为声明性语法使它易于阅读,恕我直言。