2016-10-25 11 views
0

doseqの間に変数を更新/計算する最良の方法は何ですか?投与量中の値の更新

はもちろん、私はちょうど次の操作を行うことができます:

(doseq [x xs] 
     (println (string/join " " x))) 
(println "total:" (reduce + 0 (map count xs))) 

しかし、私は値を計算するために最後にリスト全体にわたりマッピングすることを避けるためにしたい...それはちょうど数を更新するために、より理にかなっています繰り返す

私はこのであることを発見しましたが、それはちょっとしたひどいもののようです。

(defn display-xs [xs] 
    ;; all I want to do is update a count while I print, 
    ;; and have that value available afterwards! 
    (let [n (ref 0)] 
    (do 
     (doseq [x xs] 
     (dosync 
     (ref-set n (+ @n (count x))) 
     (println (string/join " " x)))) 
     (println "total:" @n)))) 

私はdoseq:letすることができますが、doseqが終了した後、私は値が必要であることを知っています。

それとも

(println "total:" (reduce (fn [m x] (do (println x) (+ m (count x)))) 0 xs)) 
+0

でそれを印刷することができます。パフォーマンスを探している場合を除き(この場合、ベンチマーク) – nha

+3

最後の 'reduce 'を使ってあなたのスニペットは私にとって完全に良いようです。 – amalloy

答えて

1

あなたがループの最大極小オーバーヘッドを心配してはいけません。異なるタスクを分離することがずっと重要です。私はあなたの最初のバージョンが大好きです。

あなたの第二のバージョンは良く見ることができるが、私はまだ最初のを好みます。

(defn display-xs [xs] 
    (let [n (atom 0)] 
    (doseq [x xs] 
     (swap! n + (count x)) 
     (println (string/join " " x))) 
    (println "total: " @n))) 
+1

2回反復する際の問題は、わずかな計算上のオーバーヘッドではありませんが、現在はリストを遅延処理していないので、すべてを一度にメモリに保持して再カウントする必要があります。 '(繰り返し1000#(make-array Object 1000000))'のような大きな要素の短いシーケンスを考えてみましょう。あなたは1MBのチャンクでそれを行うことができたときに1GBを一度にRAMに押し込みたくはありません。 – amalloy

+0

OK、私はそれが十分なサイズを提供したことを理解することができます。 – Svante

0

私はので、私はそれを行うだろう方法を示して少しあなたのコードを書き直しました:結果と

(def sample-vals (repeatedly 10 #(range (+ 5 (rand-int 10))))) 

(defn display-xs [xs] 
    (let [n (atom 0)] 
    (doseq [x xs] 
     (swap! n + (count x)) 
     (println x)) 
    (println "total:" @n))) 

(newline) 
(display-xs sample-vals) 

(defn print-n-sum [cum coll] 
    (let [cnt (count coll) ] 
    (printf "%4d: " cnt) 
    (println coll) 
    (+ cum cnt))) 

(defn calc-sum [xs] 
    (let [n (reduce print-n-sum 0 xs) ] 
    (println "total:" n))) 

(newline) 
(calc-sum sample-vals) 

あなたが(アトムを使用する必要はありません

> rs; lein run 
(0 1 2 3 4 5 6 7 8 9) 
(0 1 2 3 4 5 6 7 8 9 10 11) 
(0 1 2 3 4 5 6 7 8 9 10) 
(0 1 2 3 4 5 6 7 8 9 10 11) 
(0 1 2 3 4) 
(0 1 2 3 4 5 6 7 8 9 10 11) 
(0 1 2 3 4 5) 
(0 1 2 3 4 5 6 7 8 9 10) 
(0 1 2 3 4 5 6) 
(0 1 2 3 4 5 6 7 8 9 10) 
total: 97 

    10: (0 1 2 3 4 5 6 7 8 9) 
    12: (0 1 2 3 4 5 6 7 8 9 10 11) 
    11: (0 1 2 3 4 5 6 7 8 9 10) 
    12: (0 1 2 3 4 5 6 7 8 9 10 11) 
    5: (0 1 2 3 4) 
    12: (0 1 2 3 4 5 6 7 8 9 10 11) 
    6: (0 1 2 3 4 5) 
    11: (0 1 2 3 4 5 6 7 8 9 10) 
    7: (0 1 2 3 4 5 6) 
    11: (0 1 2 3 4 5 6 7 8 9 10) 
total: 97 

注意をこの例ではrefより簡単です)。あなたはreduceにフィードするprint-n-sumのような単一の機能で印刷と追加を行うことができます。

0

あなたは私があなただったら、私は最初のバージョンに悩まされることはない、あなたの追記機能を減らす

(defn print-and-append [acc x] 
     (println (string/join " " x)) 
     (+ acc (count x))) 

(println (reduce print-and-append 0 xs)) 
関連する問題