使用步骤和应用函数进行迭代

时间:2013-07-24 01:03:51

标签: loops clojure

我该怎么做这样的伪C ++代码:

vector<int> vs = {...};
for (i = start; i < vs.size(); i += step) {
  vs[i] *= 10;
}

在Clojure?我有这段代码:

(defn step-do [start step v]
  (if (< start (count v))
    (recur (+ start step) step (assoc v start (* 10 (v start))))
    v))

(defn -main
  [& args]
  (println (step-do 2 3 (vec (range 1 15)))))

for变体:

(defn step-do [start step v]
  (last (for [i (range start (count v) step)]
          (assoc v i (* 10 (v i))))))

什么更好?什么更快?我应该做点什么吗?

2 个答案:

答案 0 :(得分:2)

基于recur的版本非常精细,并且可能是最快的解决方案之一,但如果它可以在较大的矢量上运行,则可能需要使用瞬态。

作为一种可能的替代方案,我建议使用reduce来处理循环,输入向量作为累加器的初始值传入,而range提供的缩减序列带有步长参数

(defn step-do [start step v]
  (reduce (fn [v i]
            (assoc v i (* 10 (nth v i))))
          v
          (range start (count v) step)))

来自REPL:

(def xs (vec (range 32)))

(step-do 1 2 xs)
;= [0 10 2 30 4 50 6 70 8 90 10 110 12 130 14 150 16 170 18 190 20 210 22 230 24 250 26 270 28 290 30 310]

这有利于明确区分应用转换的索引选择(此处由range处理;如果需要,可以使用更复杂的seq生成器)和转换本身(由函数传递给reduce;广义step-do可以接受一个变换函数作为参数,而不是硬连线乘以10)。

此外,它应该是非常高效的(因为reduce对于Clojure的数据处理模型来说非常重要,因此在未来的版本中它可能会不断改进)。当然,这里也可以使用瞬态加速。

答案 1 :(得分:1)

(def an-array (int-array 25000 (int 1)))
(time (amap ^ints an-array
                  idx
                  ret
                  (* (if (zero? (mod idx step)) (int 10) (int 1))
                  (aget ^ints an-array idx))))

"Elapsed time: 14.708653 msecs"
;; Note: without type hinting the performance of would not be good.

amap