7

Clojureを使用して大きな(> 1GB)ファイルから行番号で5行を取得しようとしています。私はもうすぐそこにいますが、奇妙なことがいくつか見られます。何が起こっているのかを理解したいと思います。

これまでのところ私は持っています:

(defn multi-nth [values indices]
  (map (partial nth values) indices))

(defn read-lines [file indices]
  (with-open [rdr (clojure.java.io/reader file)]
    (let [lines (line-seq rdr)]
      (multi-nth lines indices))))

今、(read-lines "my-file" [0])問題なく動作します。ただし、渡すと[0 1]次のスタックトレースが得られます。

java.lang.RuntimeException: java.io.IOException: Stream closed
        Util.java:165 clojure.lang.Util.runtimeException
      LazySeq.java:51 clojure.lang.LazySeq.sval
      LazySeq.java:60 clojure.lang.LazySeq.seq
         Cons.java:39 clojure.lang.Cons.next
          RT.java:769 clojure.lang.RT.nthFrom
          RT.java:742 clojure.lang.RT.nth
         core.clj:832 clojure.core/nth
         AFn.java:163 clojure.lang.AFn.applyToHelper
         AFn.java:151 clojure.lang.AFn.applyTo
         core.clj:602 clojure.core/apply
        core.clj:2341 clojure.core/partial[fn]
      RestFn.java:408 clojure.lang.RestFn.invoke
        core.clj:2430 clojure.core/map[fn]

ファイルから2行目を読み取る前に、ストリームが閉じられているようです。興味深いことに、ファイルからのような行を手動で引き出すと(nth lines 200)multi-nth呼び出しはすべての値<=200で機能します。

何が起こっているのか分かりますか?

4

2 に答える 2

9

map(およびline-seq)は遅延シーケンスを返すため、with-openを呼び出すと、ファイルが閉じられるまでに、必ずしもどの行も読み取られません。

基本的に、with-openの戻り値の前に、戻り値全体を実現する必要があります。これには、doallを使用できます。

(defn multi-nth [values indices]
  (map (partial nth values) indices))

(defn read-lines [file indices]
  (with-open [rdr (clojure.java.io/reader file)]
    (let [lines (line-seq rdr)]
      (doall (multi-nth lines indices)))))

またはそのようなもの。指定された行を検索している間、multi-nthは行の先頭を保持することに注意してください。つまり、メモリ内の最後に指定された行まですべての行が保持されます。そのようにnthを使用すると、 'インデックスごとにline-seqを繰り返し実行します。これを修正する必要があります。

アップデート:

このようなものが機能します。私が好きなものより少し醜いですが、それは原則を示していると思います:ここでのインデックスはセットである必要があることに注意してください。

(defn multi-nth [values indices]
 (keep 
   (fn [[number line]] 
     (if (contains? indices number) 
       line))
   (map-indexed vector values)))

(multi-nth '(a b c d e) #{2 3})
  => c d
于 2012-08-16T22:24:46.273 に答える
5

with-file本体が実行されると、ファイルを閉じます。したがって、multi-nthが実行されると、ファイルは閉じられます。つまり、閉じられたファイルを指す遅延シーケンスが発生します。

(read-lines "my-file" [0])レイジーシーケンスの最初の要素のみが実現されるため、機能します。

この問題を修正するには、シーケンスを次のように強制的に実現する必要がありますdoall

(defn multi-nth [values indices]
  (doall (map (partial nth values) indices)))

非常に詳細な説明については、https://stackoverflow.com/a/10462159/151650を参照してください

于 2012-08-16T22:31:25.110 に答える