2013-07-24 67 views
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)))))) 

什麼是好?什麼更快?我應該做點別的嗎?

回答

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的數據處理模型來說非常重要,所以它在將來的版本中可能會不斷改進)。當然,這裏也可以使用暫態來加快速度。

+0

順便說一下,這是完全有可能的替代載體的使用本地陣列這裏(希望有一種暗示!)。然後縮減函數會使用類似'(aset arr i(* 10(aget arr i)))'的東西,集合在仍然來自'range'時減少。由於Clojure代碼片段存在問題,我用矢量的方式寫了答案,但使用'reduce'在不平凡但可預測的循環中轉換某些內容的模式更爲廣泛地適用。在這方面還值得指出的是最近推出的「縮減」提前終止。 –

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

+0

如果我使用這個函數,對於有2,3,4步等的序列,我會得到'O(n ** 2)'性能,但是我的解決方案將會在'O(n log n)'時間內運行。函數'amap'不是我想要的。 – demi

+0

如果你的問題是在本地原生數組上執行算術,這將會縮放。你可能想要做實驗。 –