Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/clojure/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Clojure 如何用更惯用的东西替换这个循环?_Clojure_Functional Programming_Idioms - Fatal编程技术网

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

Clojure 如何用更惯用的东西替换这个循环?,clojure,functional-programming,idioms,Clojure,Functional Programming,Idioms,我一直在努力,我只是花了一个小时盯着这个循环,试图把它变成一个reduce或其他“更漂亮”的循环。我被绊倒了,因为我在循环中试图达到那个目标号码,并且很早就回来了。这里的想法是随机生成一个数字(基于大小)并返回该数字处的身体部位。从概念上讲,我正在考虑将列表一分为二并返回“断点”。我还可以想象在它上面映射,然后添加一个“大小索引”进行过滤。我觉得我错过了一些简单的东西(我一直在尝试减少) 该电路有效地短路了一个减速器 此外,我还将reduce on+替换为apply(虽然效率稍低,但更清晰) 最

我一直在努力,我只是花了一个小时盯着这个循环,试图把它变成一个reduce或其他“更漂亮”的循环。我被绊倒了,因为我在循环中试图达到那个目标号码,并且很早就回来了。这里的想法是随机生成一个数字(基于大小)并返回该数字处的身体部位。从概念上讲,我正在考虑将列表一分为二并返回“断点”。我还可以想象在它上面映射,然后添加一个“大小索引”进行过滤。我觉得我错过了一些简单的东西(我一直在尝试减少)

该电路有效地短路了一个减速器

此外,我还将reduce on+替换为apply(虽然效率稍低,但更清晰)


最后一个if是返回nil,而不是如果命中从未发生,则返回累计大小。

我认为做一个约化来获得累计总和

然后找到第一个匹配密码的


将使您能够摆脱显式循环。

我在Clojure的早期课程之一是,当循环是正确的解决方案时,使用循环是正确的。原始代码并不坏,不一定需要任何改进

如果您有很多权重(大小),那么二进制搜索正确的间隔将比简单的线性搜索更好。进行二进制搜索最简单的方法可能是让Java进行搜索

(defn find-interval [intervals x]
  (Math/abs (inc (java.util.Collections/binarySearch intervals x))))
要学习的一个重要的函数习惯用法是闭包,或“忽略lambda”。我们可以通过将变量放置在返回函数的词法环境中来保存它们。在这种情况下,我们将在向量中保存预计算的累计权重之和
w
、它们的总计
n
,以及我们要从中选择的值

(defn weighted-choice-generator [choices]
  (let [weights (java.util.ArrayList. (reductions + (map second choices)))
        values (mapv first choices)
        n (last weights)]
    (fn [] (nth values (find-interval weights (long (rand n)))))))
我们将强制样本数据成为如上所述的值-权重对序列,并从加权选择生成器获取命中函数

(def hit-hobbit-asym (weighted-choice-generator 
                       (map (juxt identity :size) asym-hobbit-body-parts)))
现在进行数千次测试,以确认点击量与大小成比例:

(pprint (frequencies (repeatedly 59000 hit-hobbit-asym)))
{{:name "left-shoulder", :size 3} 2951,
 {:name "chest", :size 10} 9922,
 {:name "left-forearm", :size 3} 3046,
 {:name "left-lower-leg", :size 3} 3038,
 {:name "neck", :size 2} 1966,
 {:name "back", :size 10} 9900,
 {:name "left-ear", :size 1} 997,
 {:name "nose", :size 1} 1023,
 {:name "left-thigh", :size 4} 4020,
 {:name "left-achilles", :size 1} 972,
 {:name "left-hand", :size 2} 2075,
 {:name "left-foot", :size 2} 2062,
 {:name "left-eye", :size 1} 1047,
 {:name "left-knee", :size 2} 2068,
 {:name "left-upper-arm", :size 3} 2996,
 {:name "abdomen", :size 6} 6020,
 {:name "head", :size 3} 2933,
 {:name "left-kidney", :size 1} 986,
 {:name "mouth", :size 1} 978}

所谓的函数式编程的面包和黄油
map,reduce/fold
是关于消耗整个值序列,它们没有任何方法“打破循环”(如果它们有这样的选择,它们将使用一个额外的参数,该参数将是决定何时打破循环的谓词)。在Clojure中,reduce确实有一种方法来打破循环,
reduced
function.clojure-contrib已经过时。apply+真的比reduce+更有效吗?不管效率如何,
apply+
都有点简单易懂。@lgrapenthin好吧,我错了,我只是用短输入大小和长输入大小进行了基准测试,在这两种情况下reduce都稍微快一点。我可能记错了以前的基准测试,或者记错了结果。我将编辑答案以反映这一点。谢谢你的基准!顺便说一句,我们最近遇到了一个类似的问题,事实证明应用速度更快,所以也许你对早期基准没有错。让我找到它…不幸的是,在评论中讨论的答案被作者删除了。
(def hit-hobbit-asym (weighted-choice-generator 
                       (map (juxt identity :size) asym-hobbit-body-parts)))
(pprint (frequencies (repeatedly 59000 hit-hobbit-asym)))
{{:name "left-shoulder", :size 3} 2951,
 {:name "chest", :size 10} 9922,
 {:name "left-forearm", :size 3} 3046,
 {:name "left-lower-leg", :size 3} 3038,
 {:name "neck", :size 2} 1966,
 {:name "back", :size 10} 9900,
 {:name "left-ear", :size 1} 997,
 {:name "nose", :size 1} 1023,
 {:name "left-thigh", :size 4} 4020,
 {:name "left-achilles", :size 1} 972,
 {:name "left-hand", :size 2} 2075,
 {:name "left-foot", :size 2} 2062,
 {:name "left-eye", :size 1} 1047,
 {:name "left-knee", :size 2} 2068,
 {:name "left-upper-arm", :size 3} 2996,
 {:name "abdomen", :size 6} 6020,
 {:name "head", :size 3} 2933,
 {:name "left-kidney", :size 1} 986,
 {:name "mouth", :size 1} 978}