2014-01-04 4 views
2

Я ищу самое большое число, удовлетворяющее некоторому условию, из набора чисел, которые являются произведением всех трехзначных чисел.Как я могу изменить условие while во время цикла Clojure for-loop во время его работы?

Прямой способ заключается в следующем:

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

Но это предполагает расчетливый половину всего 900 * 900 продуктов. Если я нахожу, например, (* 380 455) соответствует моему предикату my-test?, мне не нужно искать какие-либо продукты, где любой коэффициент меньше 380. Конечно, я также хочу искать список от самого большого до самого маленького, если я делая это.

В-Clojure псевдо, я хочу сказать, что-то вроде этого:

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

где P то, что я магически установить в (min x y) каждый раз, когда я нахожу матч.

Есть ли способ сделать это в Clojure?

(Я понимаю, что я мог искать цифры по диагонали, учитывая эту конкретную проблему, которую я настроил. Однако теперь я пытаюсь решить общий случай выяснения того, как рассчитать цикл for-loop ., что некоторые его ветви нужно подрезать)

+0

Из вопроса и ограничений на 'for' переменных я заключаю, что вы пытаетесь решить Project Эйлера # 4, в этом случае вы хотите, чтобы ваш' for' возвращать один результат. В этом случае зачем использовать 'for' (который не является циклом« за », а содержит список, предназначенный для возврата списка) через' loop'/'recur'? – omiel

+0

Правильный ответ не обязательно первый, который я ударил. Хотя в качестве упражнения для себя я собираюсь попробовать 'loop' /' recur'. –

+0

@omiel прав, это намного лучший способ сделать это. Вот путь, который дает список кандидатов, которым мне тогда нужно получить '(max)' of: (loop [x 999 y 999 min 99 кандидатов []] (cond (<= x min) кандидаты \t (<= y min) (recur (dec x) 999 минутных кандидатов) \t (my-test? (* xy)) (recur x (dec y) (max min y) (кандидаты на вступление (* xy))) \t true (recur x (dec y) min) \t)) –

ответ

1

очень некрасивым решением было бы использовать 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)))) 

Одна вещь, которую я думаю, что будет мешать в том, что петля for действительно не заботится что такое «выход», поэтому я не могу понять, как он сможет получить эту информацию изначально.

«Правильное» решение, вероятно, является рекурсивным, что позволяет вам пройти (обновление a.k.a.) минимум, как вы знаете больше.

+0

Это близко к тому, что я придумал примерно через минуту после вашего ответа. Мне нужно было ввести ': when (my-test? (* X y))' в первый аргумент for-loop, чтобы P только сбрасывался при успешных совпадениях. Я согласен, что это не очень "Clojure-y". –

5

@omeil предложил loop/recur процесс, и это работает много лучше. 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 
    )) 
Смежные вопросы