0

我怎样才能做这样的伪 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))))))

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

4

2 回答 2

2

基于-recur的版本非常好,可能是最快的解决方案之一,但如果它要在更大的向量上运行,您可能希望使用瞬变。

作为一种可能的替代方法,我建议使用reduce它来处理循环,将输入向量作为累加器的初始值传入,并通过rangestep 参数提供简化的序列。

(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]

This has the benefit of clearly separating the selection of indices at which the transformation is to be applied (here handled by range; a more involved seq producer could be used if desired) and the transformation itself (captured by the function passed to reduce; a generalized step-do could accept a a transformation function as an argument, rather than hardwire multiply-by-10).

Additionally, it should be quite performant (and since reduce is quite central to Clojure's model of data handling, it's likely to keep improving in future releases). Of course here too transients could be used to speed things up.

于 2013-07-24T01:28:30.030 回答
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

于 2013-07-24T01:36:03.370 回答