2009-08-02 5 views
4

experessionが満たされるまで、以下のネストされた操作を実行したいと思います。 条件が一致したときにさらなる操作を停止するa:キーワードがありますか?clojureのような ":until"コマンドがありますか?

このコマンドは、Pythagoranトリプレット3 4 5を生成します。私は、それが数字のシーケンスに到達したら、何もしたくないです。

(for [a (range 1 100) 
     b (range 1 100) 
     c (list (Math/sqrt (+ (Math/pow (int a) 2) (Math/pow (int b) 2)))) 
     :when (= 12 (+ a b c))] 
    (list a b c)) 
+1

条件付きでは「いいえ」できませんか? – jrockway

答えて

9

:whilefor式の短絡試験です。リスト要素は、失敗したテストに初めて出会うまで生成されます。あなたのケースでは

(for [<code omitted> :while (not (= 12 (+ a b c)))] (list a b c)) 

とすぐに

一つの問題かかわらず、12に合計するトリプレットを見られるような要素を生成停止する、それはあなたが期待している何をしません。 は、テストに失敗したため、トリプレット自体は結果に含まれません。

1つのマッチング結果のみを探している場合は、リスト内包は最適な解決策ではないかもしれません。なぜループを使用しないのですか? for以来

(loop [xs (for [a (range 1 100) 
       b (range 1 100)] [a, b])] 
    (when (seq xs) 
    (let [[a, b] (first xs) 
      c (Math/sqrt (+ (Math/pow (int a) 2) 
          (Math/pow (int b) 2)))] 
     (if (not (= 12 (+ a b c))) 
     (recur (next xs)) 
     (list a b c))))) 
+0

私はそのコードから多くを学びました。ちょうどいくつかの質問:1.どのようなタイプが(....のために)生成しますか? 2.なぜあなたは(seq xs)する必要がありますか? – unj2

+0

1)レイジーシーケンス。 2)xsが空の場合をチェックする:xsが空のとき(seq xs)はnilを返し、テストに失敗してループを終了します。これはClojureのかなり一般的なイディオムです。より機能的なソリューションの場合は+1。 – alanlcode

6

あなたが最初の要素を選択することにより、望ましい結果を得るでしょうlazyシーケンスが得られます。

(first (for [a (range 1 100) 
      b (range 1 100) 
      c (list (Math/sqrt (+ (Math/pow (int a) 2) 
            (Math/pow (int b) 2)))) 
      :when (= 12 (+ a b c))] 
      (list a b c)) 

のみ生成されたリストの最初の要素が原因怠惰に計算され、そのことができます副作用とともに実証される:

user=> (first 
     (for [a (range 1 100) 
       b (range 1 100) 
       c (list (Math/sqrt (+ (Math/pow (int a) 2) 
            (Math/pow (int b) 2)))) 
       :when (= 12 (+ a b c))] 
      (do (println "working...") 
       (list a b c)))) 
working... 
(3 4 5.0) 

(for ...)来るs:a:修飾子を使用すると、リストにcを入れる必要はありません。

(for [a (range 1 100) 
     b (range 1 100) 
     :let [c (Math/sqrt (+ (Math/pow (int a) 2) 
          (Math/pow (int b) 2)))] 
     :when (= 12 (+ a b c))] 
    (list a b c)) 
+0

+1。 – firefrorefiddle

関連する問題