Optimization 在Clojure中,我可以优化扫描吗?

Optimization 在Clojure中,我可以优化扫描吗?,optimization,clojure,sequence,traversal,Optimization,Clojure,Sequence,Traversal,Chuck,以下是我使用您的解决方案后的结果: ;; Suppose we want to compute the min and max of a collection. ;; Ideally there would be a way to tell Clojure that we want to perform ;; only one scan, which will theoretically save a little time ;; First we define some da

Chuck,以下是我使用您的解决方案后的结果:

;; Suppose we want to compute the min and max of a collection.
;; Ideally there would be a way to tell Clojure that we want to perform
;; only one scan, which will theoretically save a little time  

;; First we define some data to test with
;; 10MM element lazy-seq
(def data (for [x (range 10000000)] (rand-int 100)))

;; Realize the lazy-seq 
(dorun data)

;; Here is the amount of time it takes to go through the data once
(time (apply min data))
==> "Elapsed time: 413.805 msecs"

;; Here is the time to calc min, max by explicitly scanning twice
(time (vector (apply min data) (apply max data)))
==> "Elapsed time: 836.239 msecs"

;; Shouldn't this be more efficient since it's going over the data once?
(time (apply (juxt min max) data))
==> "Elapsed time: 833.61 msecs"

由juxt执行的代码几乎完全等同于您的手写版本——
((juxt f g)x)
从字面上来说就是
[(f x)(g x)]
。它没有对集合进行任何巧妙的优化

为了满足您的需求,我认为最简单的方法是简单地折叠收藏:

test.core=> (def data (for [x (range 10000000)] (rand-int 100)))
#'test.core/data

test.core=> (dorun data)
nil

test.core=> (realized? data)
true

test.core=> (defn minmax1 [coll] (vector (apply min coll) (apply max coll)))    
#'test.core/minmax1

test.core=> (defn minmax2 [[x & xs]] (reduce (fn [[tiny big] n] [(min tiny n) (max big n)]) [x x] xs))    
#'test.core/minmax2

test.core=> (time (minmax1 data))
"Elapsed time: 806.161 msecs"
[0 99]

test.core=> (time (minmax2 data))
"Elapsed time: 6072.587 msecs"
[0 99]

这并不能准确地回答您的一般问题(即如何扫描Clojure数据结构),但值得注意的是,如果您真正关心性能,这种代码通常更适合专业数据结构/库

e、 g.使用/和一点厚颜无耻的Java互操作:

(defn minmax [[x & xs]]
  (reduce 
    (fn [[tiny big] n] [(min tiny n) (max big n)]) 
    [x x]
    xs))
i、 e.这比问题中给出的原始代码快约20-50倍


我怀疑,如果有任何代码依赖于对常规Clojure向量进行扫描,那么无论您是一次性完成的还是其他方式,您都无法接近这一点。基本上-使用正确的工具进行作业。

Hmmm所以这实际上看起来(?)稍微慢一点?我是个新手,所以我可能做错了什么。在我的机器上,使用Criterium基准测试工具,我得到了评估计数:1次调用的60个样本中有60个。执行时间平均值:1.110520秒执行时间标准偏差:50.605153毫秒执行时间下分位数:1.062179秒(2.5%)执行时间上分位数:1.194490秒(97.5%)使用的开销:8.893154ns@DerrickJohnson:我无法复制你的结果。我刚刚用这两种算法做了一个Criterium基准测试,reduce版本的速度明显快于juxt版本(reduce的平均执行时间为983.684131毫秒,而juxt的平均执行时间为2.248065秒)。我在上面添加了我的结果,看看你怎么想。你真的应该用Criterium进行基准测试,我不会惊讶于你的版本会变慢,Chuck:它只进行一次遍历,但它分配并分解了许多两个元素向量,这可能比简单地重新遍历列表要昂贵。
;; define the raw data
(def data (for [x (range 10000000)] (rand-int 100)))

;; convert to a Vectorz array
(def v (array :vectorz data))

(time (Vectorz/minValue v))
"Elapsed time: 18.974904 msecs"
0.0

(time (Vectorz/maxValue v))
"Elapsed time: 21.310835 msecs"
99.0