【问题标题】:Clojure While LoopClojure While 循环
【发布时间】:2010-11-06 10:30:30
【问题描述】:

我在尝试 clojure 我想弄清楚如何实现以下算法,

我正在从输入流中读取,我想继续阅读,直到它不是分隔符为止。

我可以在 java 中使用 while 循环来做到这一点,但我似乎无法弄清楚如何在 clojure 中做到这一点?

尽管 读 readChar != 分隔符 做一些处理...... 结束时

【问题讨论】:

    标签: java clojure loops while-loop


    【解决方案1】:

    我不知道 Clojure,但它看起来和 Scheme 一样,支持“let 循环”:

    (loop [char (readChar)]
       (if (= char delimiter)
           '()
           (do (some-processing)
               (recur (readChar)))))
    

    希望这足以让您入门。我提到了http://clojure.org/special_forms#toc9来回答这个问题。

    注意:我知道 Clojure 不鼓励副作用,所以大概你想返回有用的东西而不是 '()。

    【讨论】:

    • 正确的副作用。也许在循环中添加一个累加器以显示结果是如何在功能上构建的?
    【解决方案2】:

    在 Clojure 1.3.0 上工作,并且对于它的价值,您现在可以通过做类似的事情在 Clojure 中编写 while 循环

    (while truth-expression
      (call-some-function))
    

    【讨论】:

    • 这依赖于一些副作用来使真值表达最终变为错误。
    【解决方案3】:

    循环方法在 clojure 中可以正常工作,但是循环/递归被认为是低级操作,通常首选高阶函数。

    通常,这类问题可以通过创建一个标记序列(您的示例中的字符)并应用一个或多个 clojure 的序列函数(doseq、dorun、take-while 等)来解决

    以下示例在类 unix 系统上从 /etc/passwd 读取第一个用户名。

    (require '[clojure.java [io :as io]])
    
    (defn char-seq
      "create a lazy sequence of characters from an input stream"
      [i-stream]
      (map char 
       (take-while
        (partial not= -1)
        (repeatedly #(.read i-stream)))))
    
    ;; process the sequence one token at a time
    ;; with-open will automatically close the stream for us 
    
    (with-open [is (io/input-stream "/etc/passwd")]
      (doseq [c (take-while (partial not= \:) (char-seq is))]
        ;; your processing is done here
        (prn c)))
    

    【讨论】:

      【解决方案4】:

      我本着line-seq 的精神提出了这个想法。它完全是惰性的,并且比 loop 展示了更多 Clo​​jure 的功能特性。

      (defn delim-seq
        ([#^java.io.Reader rdr #^Character delim]
           (delim-seq rdr delim (StringBuilder.)))
        ([#^java.io.Reader rdr #^Character delim #^StringBuilder buf]
           (lazy-seq
             (let [ch (.read rdr)]
               (when-not (= ch -1)
                 (if (= (char ch) delim)
                   (cons (str buf) (delim-seq rdr delim))
                   (delim-seq rdr delim (doto buf (.append (char ch))))))))))
      

      Full paste.

      【讨论】:

      • 必须以更短的方式来做这件事。
      【解决方案5】:

      while循环通常涉及可变变量,即等待变量满足某个条件;在 Clojure 中,您通常会使用尾递归(编译器会将其转换为 while 循环)

      以下不是一个完全的解决方案,但这种 for 循环的变体在某些情况下可能会有所帮助:

      (for [a (range 100) 
            b (range 100) 
            :while (< (* a b) 1000)] 
          [a b]
        )
      

      这将创建所有 a 和 b 对的列表直到 (&lt; (* a b) 1000)。也就是说,只要满足条件,它就会停止。如果您将 :while 替换为 :when,您可以找到 所有 符合条件的对,即使找到不符合条件的对也是如此。

      【讨论】:

        【解决方案6】:

        我推出了这个版本:

        (defn read-until
          [^java.io.Reader rdr ^String delim]
          (let [^java.lang.StringBuilder salida (StringBuilder.) ]
            (while
              (not (.endsWith (.toString salida) delim))
              (.append salida (str (char (.read rdr))))
            )
            (.toString salida)
          )
        )
        

        它寻找一个字符串,而不是单个字符作为分隔符!

        谢谢!

        【讨论】:

          猜你喜欢
          • 2012-01-30
          • 2016-04-24
          • 1970-01-01
          • 1970-01-01
          • 2014-11-02
          • 2016-11-27
          • 1970-01-01
          • 1970-01-01
          • 2011-06-19
          相关资源
          最近更新 更多