Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/clojure/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Vector 在Clojure中,用什么惯用方法来前置向量?_Vector_Clojure_Append_Prepend - Fatal编程技术网

Vector 在Clojure中,用什么惯用方法来前置向量?

Vector 在Clojure中,用什么惯用方法来前置向量?,vector,clojure,append,prepend,Vector,Clojure,Append,Prepend,在列表前加上前缀很容易: user=> (conj '(:bar :baz) :foo) (:foo :bar :baz) 附加到向量很容易: user=> (conj [:bar :baz] :foo) [:bar :baz :foo] 如何(习惯用法)在返回向量的同时预加向量? 这不起作用,因为它返回的是序列,而不是向量: user=> (cons :foo [:bar :baz]) (:foo :bar :baz) 这很难看(IMVHO): 注意:我基本

在列表前加上前缀很容易:

user=> (conj '(:bar :baz) :foo)
(:foo :bar :baz)
附加到向量很容易:

user=> (conj [:bar :baz] :foo) 
[:bar :baz :foo]
如何(习惯用法)在返回向量的同时预加向量? 这不起作用,因为它返回的是序列,而不是向量:

user=> (cons :foo [:bar :baz])     
(:foo :bar :baz)
这很难看(IMVHO):


注意:我基本上只需要一个数据结构,我可以附加和前置到它。添加到大型列表会带来很大的性能损失,因此我想到了向量。

向量不是为预加而设计的。您只有O(n)个前置词:


你想要的很可能是一个。

我知道这个问题很老了,但没人说有什么不同 列表,既然你说你真的只是想要一些你可以附加的东西 在前面加上,听起来差异列表可能会对你有所帮助。 它们在Clojure似乎不受欢迎,但非常简单 要实现和手指树相比要简单得多,所以我做了一个 刚才(甚至测试了它)的列表库的微小差异。这些 在O(1)时间内串联(前置或追加)。转换差异 列表返回到一个列表应该花费O(n),如果 您正在进行大量的连接。如果你没有做很多 连接,然后只保留列表,对吗?:)

以下是这个小型库中的函数:

dl:差异列表实际上是一个包含自己的函数 包含参数并返回结果列表。每一次 生成一个差异列表,创建一个小函数 其行为类似于数据结构

dlempty:因为差异列表只是将其内容与 参数,则空的差异列表与标识相同 功能

undl:由于差异列表的作用,您可以转换 只需使用nil调用它,就可以将列表与普通列表区别开来,所以 功能不是真正需要的;这只是为了方便

dlcons:将一个项目放在列表的前面,但不是全部 这是必要的,但考虑是一个很常见的操作,它只是一个 一行程序(与这里的所有函数一样)

dlappend:包含两个不同的列表。我认为它的定义是 最有趣的——看看吧!:)

现在,这是一个很小的库——5个单行函数,给你一个O(1) 追加/前置数据结构。不错吧?啊,兰姆达的美丽 微积分

(defn-dl
“返回列表的差异列表”
[l]
(fn[x](concat l x)))
; 返回一个空的差异列表
(定义空标识)
(defn undl)
“返回差异列表的列表(只需使用nil调用差异列表即可)”
[aDl]
(每日无)
(defn-dlcons)
“将项目合并到差异列表”
[项目aDl]
(fn[x](反对项(aDl x)))
(defn-dlappend)
“附加两个差异列表”
[dl1 dl2]
(fn[x](dl1(dl2x)))
您可以通过以下方式看到它的作用:

(undl(dlappend(dl’(1233))(dl’(456)))
返回:

(123456)
这也会返回相同的内容:

((dl'(1234))(456))
享受差异列表的乐趣

更新

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

(defn dl[&elements](fn[x](concat elements x)))
(定义为“无”)
(定义dl concat[&列表](fn[x]((应用comp列表)x)))
你可以这样说:

(dl-un(dl-concat(dl-1)(dl-23)(dl)(dl-4)))
哪个会回来

(1234)

正如用户optevo在手指树回答下的评论中所说,您可以使用实现RRB树的lib:

RRB树建立在Clojure的PersistentVectors之上,添加对数时间连接和切片。ClojureScript由相同的API支持,除了缺少函数的
向量


我决定将此作为一个单独的答案发布,因为我认为这个图书馆值得这样做。它支持ClojureScript,由Clojure社区中非常有名的、致力于实现各种数据结构的ClojureScript维护。

我建议使用便利功能。例如:

(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]
相比之下,使用raw 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

如果您不害怕准量化,这个解决方案实际上相当优雅(对于“优雅”的一些定义):


实际上,我有时会在实际代码中使用它,因为声明性语法使它非常可读。

rrb向量可以在O(logn)时间内串联(因此是前置的)。看,我也推荐rrb向量。我找到了这篇文章,在挖掘Clojure邮件列表后,我找到了另外两个lib,它们应该用来替换data.finger-tree并添加ClojureScript支持。rrb vector是一个由MichałMarczyk维护的contrib项目,MichałMarczyk是Clojure社区内受人尊敬的贡献者。并不是说其他LIB的作者不是,只是我——作为Clojure的新手——不认识他们。Clojure的Vector没有真正的理由不能以与追加相同的时间复杂度进行前置。我已经在Go中实现了这一点,这里:。解决方案是1)记住“起始偏移”(默认值=0)并在所有树操作中使用它。2) 在预结束时,如果“开始偏移量”=0,则分配一个新的根节点,将旧的根节点放置在其中间,并将“开始偏移量”更新到此位置。3) 在所有其他情况下,prepend只会变成减少“开始偏移量”并在索引0处执行正常关联的情况。只有当节点将存储数据时,才延迟初始化节点,从而消除该设计中对内存浪费的担忧。通过增加“起始偏移量”并在第0个元素上执行空的assoc,可以实现
shift
操作(左侧的pop)。必须注意删除索引遵循的节点路径<“开始偏移量”将需要。我还没有研究它,但我
(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]
; 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
> `[~:foo ~@[:bar :baz]]

[:foo :bar :baz]