如何用更惯用的东西替换这个循环?

Ste*_*son 2 functional-programming idiomatic clojure

我一直在努力完成"勇敢和真实的Clojure",我只花了一个小时盯着这个循环试图将它变成一个简化或其他"更漂亮"的循环.我正试图在循环中尝试击中目标数字并提前返回时被绊倒.这里的想法是随机生成一个数字(基于大小)并返回该数字的正文部分.从概念上讲,我正在考虑将列表分成两部分并返回"断点".我还可以设想在它上面进行映射并添加"大小索引"然后进行过滤.我觉得我错过了一些简单的东西(我一直在努力减少).

(defn hit
  "Expects a sequence of maps which have a :name and :size"
  [body-parts]
  (let [body-part-size-sum (reduce + 0 (map :size body-parts))
       target (inc (rand body-part-size-sum))]
    (loop [[part & rest] body-parts
           accumulated-size (:size part)]
      (if (> accumulated-size target)
         part
        (recur rest (+ accumulated-size (:size part)))))))
Run Code Online (Sandbox Code Playgroud)

noi*_*ith 7

reduced功能有效地缩短了减少量.

另外我用apply替换了reduce on +(尽管效率稍差,但更清晰)

(defn hit
  "Expects a sequence of maps which have a :name and :size"
  [body-parts]
  (let [body-part-size-sum (apply + (map :size body-parts))
       target (inc (rand body-part-size-sum))
       found (reduce (fn [accumulated-size part]
                        (if (> accumulated-size target)
                          (reduced part)
                          (+ accumulated-size (:size part))))
                     0
                     body-parts)]
    (if (map? found) found)))
Run Code Online (Sandbox Code Playgroud)

如果命中永远不会发生,则最终if将返回nil而不是累积大小.