【问题标题】:clojure update value during doseq剂量q期间的clojure更新值
【发布时间】:2016-10-25 16:30:17
【问题描述】:

在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))

【问题讨论】:

  • 如果我是你,我不会被第一个版本所困扰。除非您正在寻找性能(在这种情况下,是基准)。
  • 你的 sn-p 在结尾加上reduce 对我来说似乎非常好。

标签: clojure


【解决方案1】:

您不必担心循环的最微不足道的开销。将不同的任务分开更为重要。我很喜欢你的第一个版本。

你的第二个版本可能会更好看,但我还是更喜欢第一个。

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

【讨论】:

  • 迭代两次的问题不是计算开销很小,而是现在你没有懒惰地处理列表,它必须一次全部保存在内存中,这样你就可以重新计算它.考虑一个短序列的大元素,例如(repeatedly 1000 #(make-array Object 1000000))。当您可以以 1MB 的块进行时,您不想一次将 1GB 推入 RAM。
  • 好的,我可以理解,提供足够的尺寸。
【解决方案2】:

我稍微重写了你的代码,所以请展示一下我会怎么做:

(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 更简单)。您可以打印并添加单个函数,例如 print-n-sum,然后将其提供给 reduce

【讨论】:

    【解决方案3】:

    你可以在你的 reduce append 函数中打印它

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

    【讨论】:

      猜你喜欢
      • 2018-08-02
      • 1970-01-01
      • 2016-07-22
      • 2020-06-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-08-01
      • 1970-01-01
      相关资源
      最近更新 更多