Clojure 使用循环递归计算winrate

Clojure 使用循环递归计算winrate,clojure,clojurescript,Clojure,Clojurescript,我得到了以下代码,calc winrate在最后一行返回[0 0 50 0 25]。我正在尝试使其返回[0 50 33.33333333333 50 60] 我是否为wins执行增量错误?当我为每次迭代打印wins的值时 (defn to-percentage [wins total] (if (= wins 0) 0 (* (/ wins total) 100))) (defn calc-winrate [matches] (let [data (r/atom [])]

我得到了以下代码,
calc winrate
在最后一行返回
[0 0 50 0 25]
。我正在尝试使其返回
[0 50 33.33333333333 50 60]

我是否为
wins
执行增量错误?当我为每次迭代打印
wins
的值时

(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}])
所以我猜我是以某种方式重置还是以某种方式nil
获胜

另外,整个循环是否可以用map/map索引之类的东西来代替?感觉map非常适合使用,但每次迭代我都需要记住上一次迭代的wins/total


谢谢

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

0
nil
1
nil
1
因此,这里要做的是维护(和更新)到目前为止的计算状态。 我们在地图上这样做那是

(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 []}
您的if应写如下:

 (if (= (get (nth matches total) :result) 1)
             (inc wins))
如果你选择一个

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

这是一个懒惰的解决方案,它使用
reductions
获得一系列运行中的赢家总数,并使用传感器1)将整数与运行中的总数相加2)将两个对分开3)将分数转换为百分比:

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

您可以按如下方式计算跑步赢取率:

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

map
在两个序列上运行:

  • (减少+(映射:结果匹配))
    -持续的赢家总数
  • (剩余(范围)))
    -
    (1 2 3…
    ,对应的匹配数
映射
ping函数,
(comp float#(*100%)/)

  • 将序列中的相应元素分开
  • 乘以100
  • 将其转换为浮点

当我转换成带有
(转换为[]
的向量时,我会得到新行上的每个条目,有什么线索吗?@Olle你是说结果会跨REPL中的多行打印吗?这是由REPL设置控制的,请参见。这不会影响结果的值,只会影响结果的打印方式。非常好地使用了带有多个集合输入的
映射
=> (calc-winrate [{:result 0} {:result 1} {:result 0} {:result 1} {:result 1}])
(0.0 50.0 33.333332 50.0 60.0)