简体   繁体   English

Clojure:当当前变量的值与输入的值匹配时,如何使for循环停止?

[英]Clojure: How do I have a for loop stop when the value of the current variable matches that of my input?

Preface Firstly, I'm new to Clojure and programming, so I thought I'd try to create a function that solves a non-trivial equation using my natural instincts. 序言首先,我是Clojure和编程的新手,所以我认为我想尝试使用我的自然本能创建一个求解平凡方程的函数。 What resulted is the desire to find a square root. 结果就是渴望找到平方根。

The question What's the most efficient way to stop my square-n-map-maker function from iterating past a certain point? 问题是什么阻止我的square-n-map-maker函数迭代经过某个点的最有效方法是什么? I'd like to fix square-n-map-maker so that I can comment out the square-maker function which provides me with the results and format I currently want to see but not the ability to recall the square-root answer (insofar as I know). 我想修复square-n-map-maker,以便可以注释掉square-maker函数,该函数为我提供了我当前想要查看的结果和格式,但无法调用平方根答案(insofar我所知)。

Ie I want it to stop when it is greater than or equal to my input value 即我希望它大于或等于输入值时停止

My initial thought was that instead of a keyword list, I would want it to be a map. 我最初的想法是,我希望它不是地图,而是关键字列表。 But I'm having a very difficult time getting my function to give me a map. 但是我很难获得要给我的地图的功能。 The whole reason I wanted a map where one member of a pair is n and another is n^2 so that I could extract the actual square root from it and it give it back to the user as the answer. 我想要一个映射的全部原因是,一对映射中的一个是n,另一个是n ^ 2,这样我就可以从中提取出实际的平方根,并将其作为答案返回给用户。

Any ideas on the best way to accomplish this? 对实现此目标的最佳方法有何想法? (below is the function I want to fix) (下面是我要修复的功能)

;; attempting to make a map so that I can comb over the 
;; map later and recall a value that meets
;; my criteria to terminate and return result if (<= temp-var input)

(defn square-n-map-maker [input] (for [temp-var {remainder-culler input}]
                                   (map list(temp-var) (* temp-var temp-var))
                                 )
)
(square-n-map-maker 100) => clojure.lang.ArityException: Wrong number of args (0) passed to: MapEntry
         AFn.java:437 clojure.lang.AFn.throwArity
          AFn.java:35 clojure.lang.AFn.invoke

/Users/dbennett/Dropbox/Clojure Files/SquareRoot.clj:40 sqrt-range-high-end/square-n-map-maker[fn] /用户/ dbennett / Dropbox / Clojure文件/SquareRoot.clj:40 sqrt范围高端/ square-n-map-maker [fn]

The following is the rest of my code 以下是我的其余代码

;; My idea on the best way to find a square root is simple.
;; If I want to find the square root of n, divide n in half
;; Then find all numbers in 0...n that return only a remainder of 0.
;; Then find the number that can divide by itself with a result of 1.
;; First I'll develop a function that works with evens and then odds
(defn sqrt-range-high-end [input] (/ input 2))
(sqrt-range-high-end 100) => 50

(defn make-sqrt-range [input] (range (sqrt-range-high-end (+ 1 input))))
(make-sqrt-range 100) =>(0 1 2 3 4 5 6 ... 50)    
(defn zero-culler [input] (remove zero? (make-sqrt-range input)))
(zero-culler 100) =>(1 2 3 4 5 6 ... 50) 

(defn odd-culler [input] (remove odd? (zero-culler input)))
(odd-culler 100) => (2 4 6 8 10...50)    

(defn even-culler [input] (remove even? (zero-culler input)))
(even-culler 100) => (1 3 5 7...49)

(defn remainder-culler [input] (filter #(zero? (rem input %)) (odd-culler input)))
(remainder-culler 100) => (2 4 6 12 18)

(defn square-maker [input] (for [temp-var (remainder-culler input)]
                           (list (keyword (str
                                             temp-var" "
                                             (* temp-var temp-var)
                                           )
                                 )
                           )
                       )
(square-maker 100) => ((:2 4) (:4 16) (:10 100) (:20 400) (:50 2500))

Read the Error Messages! 阅读错误消息!

You're getting a little ahead of yourself! 您会变得有点领先! Your bug has nothing to do with getting for to stop "looping." 你的错误无关,与得到for停止“循环”。

(defn square-n-map-maker [input] (for [temp-var {remainder-culler input}]
                                   (map list(temp-var) (* temp-var temp-var))))
(square-n-map-maker 100) => clojure.lang.ArityException: Wrong number of args (0) passed to: MapEntry
          AFn.java:437 clojure.lang.AFn.throwArity
          AFn.java:35 clojure.lang.AFn.invoke

Pay attention to error messages. 注意错误消息。 They are your friend. 他们是你的朋友。 In this case, it's telling you that you are passing the wrong number of arguments to MapEntry (search for IPersistentMap ). 在这种情况下,它告诉您您将错误数量的参数传递给MapEntry (搜索IPersistentMap )。 What is that? 那是什么?

{} creates a map literal. {}创建一个地图文字。 {:key :value :key2 :value2} is a map. {:key :value :key2 :value2}是一个映射。 Maps can be used as if they were functions: 可以像使用地图一样使用地图:

 > ({:key :value} :key)
 :value

That accesses the entry in the map associated with key. 这将访问与键关联的映射中的条目。 Now, you created a map in your first line: {remainder-culler input} . 现在,您在第一行中创建了一个地图: {remainder-culler input} You just mapped the function remainder-culler to the input. 您刚刚将函数rest-culler映射到了输入。 If you grab an item out of the map, it's a MapEntry . 如果您从地图中抓取一个项目, MapEntry Every MapEntry can be used as a function, accepting an index as an argument, just like a Vector: 每个MapEntry都可以用作函数,接受索引作为参数,就像Vector一样:

> ([:a :b :c :d] 2)
:c

Your for is iterating over all MapEntries in {remainder-culler input} , but there's only one: [remainder-culler input] . 您的for迭代了{remainder-culler input}所有MapEntries,但是只有一个: [remainder-culler input] This MapEntry gets assigned to temp-var . 该MapEntry被分配给temp-var

Then in the next line, you wrapped this map in parentheses: (temp-var) . 然后在下一行中,将此地图用括号括起来: (temp-var) This forms an S-expression , and expressions are evaluated assuming that the first item in the expression is a function/procedure. 这形成一个S表达式 ,并假定表达式中的第一项是函数/过程来评估表达式。 So it expects an index (valid indices here would be 0 and 1). 因此,它需要一个索引(此处的有效索引为0和1)。 But you pass no arguments to temp-var . 但是您没有将参数传递给temp-var Therefore: clojure.lang.ArityException: Wrong number of args . 因此: clojure.lang.ArityException: Wrong number of args

Also, note that map is not a constructor for a Map . 另外,请注意map不是Map的构造函数。

Constructing a map 构造地图

Now, on to your problem. 现在,解决您的问题。 Your square-maker is returning a list nicely formatted for a map, but it's made up of nested lists. 您的square-maker返回的列表格式正确,但列表由嵌套列表组成。

Try this: 尝试这个:

(apply hash-map (flatten (square-maker 100)))

Read this page and this page to see how it works. 阅读此页此页以了解其工作原理。

If you don't mind switching the order of the keys and values, you can use the group-by that I mentioned before : 如果您不介意切换键和值的顺序,则可以使用前面提到group-by

(defn square-maker [input]
    (group-by #(* % %) (remainder-culler input)))
(square-maker 100) => {4 [2], 16 [4], 100 [10], 400 [20], 2500 [50]}

Then you can snag the value you need like so: (first ((square-maker 100) 100)) . 然后,您可以像这样获取所需的值: (first ((square-maker 100) 100)) This uses the map-as-function feature I mentioned above. 这使用了我上面提到的“功能映射”功能。

Loops 循环

If you really want to stick with the intuitive looping concept, I would use loop , not for . 如果您真的想坚持直观的循环概念,则可以使用loop ,而不是for for is lazy, which means that there is neither means nor reason (if you use it correctly) to "stop" it -- it doesn't actually do any work unless you ask for a value from it, and it only does the work it must to give you the value you asked for. for是懒惰的,这意味着没有任何手段或理由(如果正确使用它)“停止”它-除非您从中要求一个值,否则它实际上不会做任何工作,并且它只会工作它必须给您您所要求的价值。

(defn square-root [input]
    (let [candidates (remainder-culler input)]
         (loop [i 0]
            (if (= input (#(* % %) (nth candidates i)))
                (nth candidates i)
                (recur (inc i))))))

The embedded if determines when the looping will cease. 嵌入式if决定循环何时终止。

But notice that loop only returns its final value (acquaint yourself with loop 's documentation if that sentence doesn't make sense to you). 但是请注意, loop只会返回其最终值(如果您认为那句话对loop没有意义,请熟悉loop的文档)。 If you want to build up a hash-map for later analysis, you'd have to do something like (loop [i 0, mymap {}] ... . But why analyze later if it can be done right away? :-) 如果要建立一个哈希图以供以后分析,则必须做类似的事情(loop [i 0, mymap {}] ...但是为什么以后可以立即进行分析呢?:- )

Now, that's a pretty fragile square-root function, and it wouldn't be too hard to get it caught in an infinite loop (feed it 101). 现在,这是一个非常脆弱的平方根函数,将它陷入无限循环(输入101)并不难。 I leave it as an exercise to you to fix it (this is all an academic exercise anyway, right?). 我将其作为练习来解决它(无论如何这都是学术练习,对吗?)。

I hope that helps you along your way, once again. 希望对您有帮助。 I think this is a great problem for learning a new language. 我认为这对于学习新语言是一个很大的问题。 I should say, for the record, though, that once you are feeling comfortable with your solution, you should search for other Clojure solutions to the problem and see if you can understand how they work -- this one may be "intuitive," but it is not well-suited to Clojure's tools and capabilities. 作为记录,我应该说,一旦您对解决方案感到满意,就应该搜索该问题的其他Clojure解决方案 ,看看您是否能够理解它们的工作原理,这可能是“直观的”,但是它不太适合Clojure的工具和功能。 Looking at other solutions will help you grasp Clojure's world a bit better. 寻找其他解决方案将帮助您更好地掌握Clojure的世界。

For more reading: 欲了解更多信息:

Imperative looping with side-effects. 命令式循环具有副作用。

How to position recur with loop 如何使用loop定位recur

The handy into 方便into

Finally, this "not constructive" list of common Clojure mistakes 最后, 此“非建设性”的常见Clojure错误列表

for is not a loop, and it's not iterating. for不是循环,也不是迭代。 It lazily creates a list comprehension, and it only realizes values when required (in this case, when the repl tries to print the result of the evaluation). 它懒惰地创建列表推导,并且仅在需要时实现值(在这种情况下,当repl尝试打印评估结果时)。 There are two usual ways to do what you want: one is to wrap square-maker in 有两种通常的方式来做您想要的事情:一种是将square-maker包装在

(first (filter some-predicate (square-maker number))) to obtain the first element in the sequence that complies with some-predicate. (first (filter some-predicate (square-maker number)))以获取符合some-predicate的序列中的第一个元素。 Eg 例如

(first (filter #(and (odd? %) (< 50 %)) (range))) => 51 (first (filter #(and (odd? %) (< 50 %)) (range))) => 51

The above won't realize the infinite range, obviously. 以上显然不会实现无限范围。

The other one is not to use a list comprehension and do it in a more imperative way: run an actual loop with a termination condition (see loop and recur ). 另一种方法是不使用列表推导,而是以更强制的方式执行列表推导:使用终止条件运行实际的循环(请参见looprecur )。

Example: 例:

(loop [x 0]
  (if (and (odd? x) (> x 50))
    x
    (recur (inc x))))

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何创建一个循环来生成随机数,直到它与我的用户输入匹配? - How do I create a loop that will generate random numbers until it matches my user input? 我如何使循环停止 - How do I make my loop stop LabVIEW:与数组中的值匹配并返回索引时,如何中断循环 - LabVIEW: How do I break a loop when it matches a value in the array and returns the index 我如何停止循环吐出最后一次输入两次 - c++ How do I stop my loop from spitting out the last input twice 如何使该程序检查输入是否为 integer 而不会导致运行时错误并使用标记值停止循环? - How do I make this program check if an input is an integer without causing an error in runtime and stop the loop with a sentinel value? 当输入小于九时,如何停止我的 golang 循环? - How can I stop my golang loop when the input less than nine? 如何在 function 的每个循环之后停止重新定义变量? - How do I stop redefining a variable after every loop of a function? 当我有一个except参数时,如何不在Python的循环中声明变量 - How do I not declare a variable in a loop in Python when I have an except argument 当达到某个索引值时,如何停止将数字添加到列表中的 while 循环? - How do I stop a while loop that adds numbers to a list when a certain index value is reached? 如何让我的脚本循环遍历所有变量组合,然后让它停止并在条件不满足时尝试下一个组合? - How do I get my script to cycle through all variable combinations, then have it stop and try the next combination if a condition isnt fulfilled?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM