我正在尝试从Clojure向量中删除元素:
请注意,我正在使用来自Kotlin的Clojure操作
val set = PersistentHashSet.create("foo")
val vec = PersistentVector.create("foo", "bar")
val seq = clojure.`core$remove`.invokeStatic(set, vec) as ISeq
val resultVec = clojure.`core$vec`.invokeStatic(seq) as PersistentVector
这相当于以下Clojure代码:
(remove #{"foo"} ["foo" "bar"])
代码工作正常,但我注意到从seq创建一个向量非常慢。我写了一个基准,这些是结果:
| Item count | Remove ms | Remove with converting back to vector ms|
-----------------------------------------------------------------
| 1000 | 51 | 1355 |
| 10000 | 71 | 5123 |
您是否知道我如何将seq
操作产生的remove
转换回vector
而不会造成严重的性能损失?
如果不可能有另一种方法来执行remove
操作?
答案 0 :(得分:6)
你要做的事情从根本上表现得很糟糕。向量用于快速索引读/写,O(1)访问右端。要做任何其他事情,你必须拆开矢量并再次重建它,进行O(N)操作。如果您需要这样的操作才能有效,则必须使用不同的数据结构。
答案 1 :(得分:4)
您可以尝试对返回向量的remove
进行补充操作:
(filterv (complement #{"foo"})
["foo" "bar"])
请注意filterv
的使用。 v
表示它从一开始就使用向量,并返回一个向量,因此不需要转换。它在幕后使用transient
向量,所以它应该非常快。
我使用complement
否定谓词,因此我可以使用filterv
,因为没有removev
。 remove
is just defined as the complement
of filter
anyway though,所以它基本上就是你所做的,只是严格的。
答案 2 :(得分:0)
为什么不使用PersistentHashSet?快速删除,但没有订购。我模糊地回忆起Clojure也有一个排序集,以备不时之需。
答案 3 :(得分:0)
您接受var path = location.href.replace(/[^\?]+$/,$('form').serialize());
var cpy = $('input#cpy').val(path);
cpy.select();
document.execCommand('copy');
的惰性结果等同于转换回向量的具体结果时出错了。将remove
的惰性结果与(remove ...)
隐含的具体结果进行比较。你会发现它比仅仅(count (remove ...))
稍慢。此外,对于真正的速度关键型应用程序,没有什么比使用本机Java (vec (remove ...))
:
ArrayList
结果:
(ns tst.demo.core
(:require
[criterium.core :as crit] )
(:import [java.util ArrayList]))
(def N 1000)
(def tgt-item (/ N 2))
(def pred-set #{ (long tgt-item) })
(def data-vec (vec (range N)))
(def data-al (ArrayList. data-vec))
(def tgt-items (ArrayList. [tgt-item]))
(println :lazy)
(crit/quick-bench
(remove pred-set data-vec))
(println :lazy-count)
(crit/quick-bench
(count (remove pred-set data-vec)))
(println :vec)
(crit/quick-bench
(vec (remove pred-set data-vec)))
(println :ArrayList)
(crit/quick-bench
(let [changed? (.removeAll data-al tgt-items)]
data-al))