【发布时间】:2012-12-19 02:37:21
【问题描述】:
我有一对向量 x 和 y 的唯一项目,我知道每个项目都需要排序。我希望有两者的交集,保持排序顺序。理想情况下,结果将是另一个向量,用于快速随机访问。
下面的生成只是为了举例,我的x 和y 将预先排序和预先区分(它们实际上是时间样本)。
(defn gen-example [c] (-> (repeatedly c #(-> c rand int)) distinct sort vec))
user=> (def x (gen-example 100000)) (count x)
#'user/x
63161
user=> (def y (gen-example 100000)) (count y)
#'user/y
63224
我知道 Clojure 有 clojure.set/intersection 可以在 sorted-set 上工作。我的x 和y 具有相同的属性(已排序的不同元素),但类型不同。
问题 1:鉴于 x 和 y 到 sorted-sets 已经不同且已排序,是否有更好/更快的方法将它们转换为 sorted-sets?
user=> (time (def ssx (apply sorted-set x)))
"Elapsed time: 607.642592 msecs"
user=> (time (def ssy (apply sorted-set y)))
"Elapsed time: 617.046022 msecs"
现在我已经准备好执行我的交叉路口了
user=> (time (count (clojure.set/intersection ssx ssy)))
"Elapsed time: 355.42534 msecs"
39992
这有点令人失望,粗略地看一下(source clojure.set/intersection) 似乎并没有对这些集合进行排序这一事实进行任何特殊处理。
问题 2:有没有比clojure.set/intersection 更好/更快的方法来执行sorted-sets 的交集?
(defn intersect-sorted-vector [x y]
(loop [x (seq x) y (seq y) acc []]
(if (and x y)
(let [x1 (first x)
y1 (first y)]
(cond
( < x1 y1) (recur (next x) y acc)
( > x1 y1) (recur x (next y) acc)
:else (recur (next x) (next y) (conj acc x1))))
acc)))
事实证明这是一个很好的交易(近 10 倍)。
user=> (time (count (intersect-sorted-vector x y)))
"Elapsed time: 40.142532 msecs"
39992
但是,我不禁觉得我的代码过于程序化/迭代。
问题 3:谁能提出一种更惯用的方法来处理 Clojure 中的一对向量?
【问题讨论】: