简体   繁体   English

如何在Clojure for循环运行时更改:while条件?

[英]How can I change the :while condition on a Clojure for-loop while it is running?

I'm searching for the biggest number meeting some condition, out of the set of numbers that are the product of all three-digit numbers. 我正在从所有三位数数字的乘积中搜索满足某些条件的最大数字。

The straightforward way is this: 直接的方法是这样的:

(apply max (filter 
            my-test? 
            (for [x (range 100 1000)
                  y (range x 1000)]
              (* x y))))

But this involves calculating half of all 900*900 products. 但这涉及计算所有900 * 900产品的一半。 If I find, eg, (* 380 455) matches my my-test? 如果我发现例如(* 380 455)符合my-test? predicate, I don't need to search any products where either factor is less than 380. Of course, I will also want to search the list from the biggest to the smallest if I'm doing this. 谓词,我不需要搜索任何因子均小于380的产品。当然,如果要这样做,我也想从最大到最小搜索列表。

In psuedo-Clojure, I want to say something like this: 在psuedo-Clojure中,我想说这样的话:

(for [x (range 999 99 -1) :while (>= x P)
      y (range x 99 -1) :while (>= y P)]
  (* x y))

where P is something I magically set to (min xy) each time I find a match. 其中P是我每次找到匹配项时都会神奇地设置为(min xy)的值。

Is there a way to do this in Clojure? Clojure有办法做到这一点吗?

(I realize I could search the numbers in a diagonal fashion, given this specific problem I've set up. However, I'm now trying to solve for the general case of figuring out how to tell the for-loop that some its branches need pruned.) (考虑到我已经设置的这个特定问题,我意识到我可以对角线形式搜索数字。但是,我现在正在尝试解决一般情况,以弄清楚如何告诉for循环某些分支需要修剪。)

@omeil suggested a loop / recur process, and this works much better. @omeil建议一loop / recur的过程,而这个效果好得多。 for loops just aren't built for this. for循环不是为此而构建的。

(loop [x 999 y 999 min 99 candidates []]
    (cond (<= x min)          candidates ; exit condition
          (<= y min)          (recur (dec x) 999 min candidates) ; step x
          (my-test? (* x y)) (recur x (dec y) (max min y) (conj candidates (* x y)))
          :else               (recur x (dec y) min candidates) ; step y
     ))

A very ugly solution would be to use an atom : 一个非常丑陋的解决方案是使用atom

(let [P (atom 0)]
  (for [x (range 999 99 -1) :while (>= x @P)
        y (range x 99 -1)   :while (>= y @P)]
    (do
      (reset! P (+ x y))
      (* x y))))

One thing that I think will get in the way is that the for loop doesn't really care what the "output" is, so I am unable to see how it would be able to get that information natively. 我想会遇到的一件事是for循环并不真正在乎“输出”是什么,因此我无法看到它将如何从本地获取信息。

The "right" solution is probably a recursive one that allows you to pass in (aka update) your minimum as you know more. “正确”的解决方案可能是一种递归解决方案,它使您可以了解更多而传递(又称为更新)最小值。

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM