【问题标题】:Clojure lazily read random line from fileClojure 懒惰地从文件中读取随机行
【发布时间】:2015-11-03 16:56:25
【问题描述】:

我有一个 txt 文件中的示例数据集。数据文件非常大,因此不能将其加载到内存中。我需要能够懒惰地读取文件。此外,我需要以随机顺序阅读这些行。在某些情况下,我不需要阅读所有行。这是我目前发现的 -

(defn read-lazy [in-file]
        (letfn [(helper [rdr]
                            (if-let [line (.readLine rdr)]
                                (cons line (helper rdr))
                                (do (.close rdr) nil)))]
            (helper (io/reader in-file))))

返回文件的惰性序列。当我需要时,如何循环遍历惰性序列中的随机行?我认为在这里使用 go 块可能会有所帮助。 Go 块可以在通道中放置一条随机线并等待某些东西消耗它。一旦数据被读取,它就会在通道中放置另一行等待下一次读取。我该如何实施?

这是我的计算方法(不是随机的)-

(def lazy-ch (chan))
(defn async-fetch-set [in-file]
    (go
        (with-open [reader (io/reader in-file)]
            (doseq [line (line-seq reader)]
                (>! lazy-ch line)))
        (close! lazy-ch)))

(println "got: " (<!! lazy-ch))

这是解决问题的好方法吗?有更好的解决方案吗?我可能不需要阅读所有行,所以我希望能够在需要时关闭阅读器。

【问题讨论】:

  • 所以,为了确保我正确理解您的问题:您需要对文件的每一行按顺序执行相同的操作,但该序列的顺序需要是随机的?
  • 是的。这就是我想要做的。我添加了一个更新

标签: file asynchronous clojure lazy-sequences


【解决方案1】:

您上面的解决方案不包括任何随机性。 Go 通道是先进先出的结构。如果真的要随机读取,首先需要统计文件中的行数,然后使用(rand N)在区间[0..N-1]内生成整数I,然后读取行I从文件中。

有几种不同的方法可以从文件中读取行 I,它们在速度与内存要求之间进行权衡。

【讨论】:

    【解决方案2】:
    (defn char-seq
      "Returns a lazy sequence of characters from rdr. rdr must implement
      java.io.Reader."
      [rdr]
      (let [c (.read rdr)]
        (if-not (neg? c)
          (cons (char c) (lazy-seq (char-seq rdr))))))
    
    (defn line-offsets
      "Returns a lazy sequence of offsets of all lines in s."
      [s]
      (if (seq s)
        (->> (partition-all 3 1 s)
             (map-indexed
              (fn [i [a b c]]
                (cond
                  (= b \newline) (if c (+ 2 i))
                  (= a \return) (if b (inc i)))))
             (filter identity)
             (cons 0))))
    
    (defn ordered-line-seq
      "Returns the lines of text from raf at each offset in offsets as a lazy
      sequence of strings. raf must implement java.io.RandomAccessFile."
      [raf offsets]
      (map (fn [i]
             (.seek raf i)
             (.readLine raf))
           offsets))
    

    示例用法:

    (let [filename "data.txt"
          offsets (with-open [rdr (clojure.java.io/reader filename)]
                    (shuffle (line-offsets (char-seq rdr))))]
      (with-open [raf (java.io.RandomAccessFile. filename "r")]
        (dorun (map println (ordered-line-seq raf offsets)))))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-08-13
      • 1970-01-01
      • 2016-02-19
      • 1970-01-01
      • 2012-12-29
      • 1970-01-01
      • 1970-01-01
      • 2011-10-16
      相关资源
      最近更新 更多