1

次の内容の入力ファイルがあります。

2
stuff-11
stuff-12
3
stuff-21
stuff-22
stuff-23
1
stuff-31

次の結果を取得したい:

([stuff-11 stuff-12] [stuff-21 stuff-22 stuff-23] [stuff-31])

私の最初の解決策は、次のように、アキュムレータで再帰を使用することでした。

(defn parse-input [lines accum]
   (if (= 0 (count lines))
       accum
       (let [[line-num (Integer. (first lines))]
             [head tail] (split-at (+ 1 line-num) lines)]
             [stuff (vec (drop 1 head))]]
            (parse-input tail (concat accum [stuff]))))
(def result (parse-input input []))

しかし、私の知る限り、Clojure では JVM の TCO が不足しているため、再帰関数は慣用的ではありません。

この問題を解決するより良い方法はありますか?

4

2 に答える 2

1
user=> (require '[clojure.string :as s])
nil
user=> (require '[clojure.edn :as edn])
nil
user=> (keep-indexed #(if (odd? %) %2) 
                     (partition-by (comp number? edn/read-string) 
                     (s/split-lines (slurp "/tmp/input.txt"))))
(("stuff-11" "stuff-12") ("stuff-21" "stuff-22" "stuff-23") ("stuff-31"))

ここ/tmp/input.txtには、指定したテキストが含まれています。

#(if (odd? %) %2)結果としてベクトルのシーケンスが必要な#(if (odd? %) (vec %2))場合は、に置き換えます。

于 2013-04-14T21:15:21.800 に答える
1

私は Michiel Borkent の答えがいくつかの理由で好きではありません。そのうちの 1 つは((comp number? read-string) "3 blah blahb stuff and etc")true を返すという事実です。また、簡潔かもしれませんが、それほど直感的でも拡張可能でもありません。

再帰を使用する正しい直感があったと思いますが、遅延 seq はより慣用的です。

(defn parse-stuff [text]
  (let [step (fn step [[head & tail]]
               (when-let [n (clojure.edn/read-string head)] 
                 (cons (vec (take n tail))
                   (lazy-seq (step (drop n tail))))))]
     (step (clojure.string/split-lines text))))
于 2013-04-14T23:50:09.160 に答える