用循环递归计算胜率

Calculate winrate with loop recur

(defn to-percentage [wins total]
  (if (= wins 0) 0
      (* (/ wins total) 100)))

(defn calc-winrate [matches]
  (let [data (r/atom [])]
    (loop [wins 0
           total 0]
      (if (= total (count matches))
        @data
        (recur (if (= (get (nth matches total) :result) 1)
                 (inc wins))
               (do
                 (swap! data conj (to-percentage wins total))
                 (inc total)))))))

(calc-winrate [{:result 0} {:result 1} {:result 0} {:result 1} {:result 1}])

我得到以下代码,calc-winrate 在最后一行 returns [0 0 50 0 25]。我正在努力 return [0 50 33.33333333333333 50 60].

我对 wins 的增量是否错误?当我为每次迭代打印 wins 的值时,我得到

0
nil
1
nil
1

所以我猜我不知何故重置或零 wins 不知何故?

此外,是否可以将整个循环替换为 map/map-indexed 或其他内容?感觉 map 使用起来很完美,但我需要在每次迭代时牢记上一次迭代 wins/total。

谢谢!

这里有一个 reduce 的解决方案:

(defn calc-winrate [matches]
  (let [total-matches (count matches)]
    (->> matches
         (map :result)
         (reduce (fn [{:keys [wins matches percentage] :as result} match]
                  (let [wins (+ wins match)
                        matches (inc matches)]
                    {:wins wins
                     :matches matches
                     :percentage (conj percentage (to-percentage wins matches))}))
                 {:wins 0 
                  :matches 0
                  :percentage []}))))

所以这里的事情是维护(和更新)到目前为止的计算状态。 我们在

的地图中这样做
 {:wins 0
  :matches 0
  :percentage []}

Wins 将包含到目前为止的胜利,matches 是我们分析的比赛数量,percentage 是到目前为止的百分比。

 (if (= (get (nth matches total) :result) 1)
             (inc wins))

你的if应该这样写:

 (if (= (get (nth matches total) :result) 1)
             (inc wins)
             wins  ; missing here , other wise it will return a nil, binding to wins in the loop
)

如果你选择降价,

(defn calc-winrate2 [ x y ]
  (let [ {total :total r :wins  } x
        {re :result } y]
    (if (pos? re )
      {:total (inc total) :wins (inc r)}
      {:total (inc total) :wins r}
      )
    )
  )

(reductions calc-winrate2 {:total 0 :wins 0} [   {:result 0} {:result 1} {:result 0} {:result 1} {:result 1}])

这是一个懒惰的解决方案,使用 reductions 获得一系列 运行 获胜总计,并且换能器 1) 将轮数与 运行 总计相结合 2) 划分对3) 将分数转换为百分比:

(defn calc-win-rate [results]
  (->> results
       (map :result)
       (reductions +)
       (sequence
         (comp
           (map-indexed (fn [round win-total] [win-total (inc round)]))
           (map (partial apply /))
           (map #(* 100 %))
           (map float)))))

(calc-win-rate [{:result 0} {:result 1} {:result 0} {:result 1} {:result 1}])
=> (0.0 50.0 33.333332 50.0 60.0)

您可以按如下方式计算 运行 胜率:

(defn calc-winrate [matches]
  (map
    (comp float #(* 100 %) /)
    (reductions + (map :result matches))
    (rest (range))))

例如,

=> (calc-winrate [{:result 0} {:result 1} {:result 0} {:result 1} {:result 1}])
(0.0 50.0 33.333332 50.0 60.0)

map 对两个序列进行操作:

  • (reductions + (map :result matches)) - 运行 总胜利;
  • (rest (range)))) - (1 2 3 ... ),对应的匹配数。

mapping 函数,(comp float #(* 100 %) /)

  • 划分序列对应的元素,
  • 乘以 100,
  • 将其转换为浮点数。