Clojure 懒惰地从文件中读取随机行

Posted

技术标签:

【中文标题】Clojure 懒惰地从文件中读取随机行【英文标题】:Clojure lazily read random line from file 【发布时间】: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))

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

【问题讨论】:

所以,为了确保我正确理解您的问题:您需要对文件的每一行按顺序执行相同的操作,但该序列的顺序需要是随机的? 是的。这就是我想要做的。我添加了一个更新 【参考方案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)))))

【讨论】:

以上是关于Clojure 懒惰地从文件中读取随机行的主要内容,如果未能解决你的问题,请参考以下文章

从巨大的 CSV 文件中读取随机行

读取随机行 com 文件

读取大型 csv 文件、python、pandas 的随机行

R:使用 fread 或等价物从文件中读取随机行?

从STDIN读取文件并打印随机行。

在Unix命令行中从文件中读取随机行的简单方法是什么?