如何在Clojure中快速删除矢量中的元素?

时间:2018-02-04 13:55:53

标签: optimization data-structures collections clojure

我正在尝试从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操作?

4 个答案:

答案 0 :(得分:6)

你要做的事情从根本上表现得很糟糕。向量用于快速索引读/写,O(1)访问右端。要做任何其他事情,你必须拆开矢量并再次重建它,进行O(N)操作。如果您需要这样的操作才能有效,则必须使用不同的数据结构。

答案 1 :(得分:4)

您可以尝试对返回向量的remove进行补充操作:

(filterv (complement #{"foo"}) 
         ["foo" "bar"])

请注意filterv的使用。 v表示它从一开始就使用向量,并返回一个向量,因此不需要转换。它在幕后使用transient向量,所以它应该非常快。

我使用complement否定谓词,因此我可以使用filterv,因为没有removevremove 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))