2014-10-12 248 views
1

我有一個大的CSV不會完全適合內存,我需要做很多工作。我是懶惰序列的新手,不知道如何解決這個問題。我試圖將整個文件讀入內存,然後解析它,我知道這是錯誤的。雙讀取大CSV文件

這裏就是我想要做的事:

  1. 閱讀標題行和以此爲基礎進行的事情。它在整個程序中使用。
  2. 閱讀所有行並收集每列的彙總數據。
  3. 使用匯總數據轉換原始數據並寫入新文件。

有沒有一種方法可以讀取標題行並不斷地使用它,而不會導致懶惰序列的「保持頭部」問題,將整個事件保留在內存中?

我發現這個相關線程:using clojure-csv.core to parse a huge csv file

+0

逐行解析文件兩次,行。第一遍收集您的摘要信息;在第二遍時執行轉換並將結果逐行寫入新文件。 – 2014-10-12 02:58:42

+0

我會用'let'來定義兩個不同的符號還是重複使用同一個符號?爲什麼這樣避免「頭痛醫頭」? – user1559027 2014-10-12 06:45:15

+0

請查看我對句子問題的修訂是否通過詢問具體結果的可能性而將本文從「主要基於意見」移出。 – user1559027 2014-10-13 23:20:11

回答

2

Clojure的負責清除本地綁定的,所以一旦綁定不再將被使用,它會被清零,使之符合要求的供GC。所以,你的代碼可能看起來是這樣的:

(defn gather-summary [file] 
    (with-open [rdr (io/reader file)] 
     (let [lines (csv/read-csv rdr) 
      header (first lines)] 
      (reduce (fn [so-far row] 
        (if header 
        (inc so-far) 
        (dec so-far))) 
       0 
       (rest lines)))) 

(defn modify [summary file] 
    ;similar to gather 
    ) 

(defn process [file] 
    (let [summary (gather-summary file)] 
     (modify summary file))) 

header不成立的頭,因爲它只是第一個元素,它不具有任何裁判線的其餘部分。

lines在調用(rest lines)後沒有使用,所以Clojure會清除它。

reduce作品上遞歸的方式,所以Clojure中也需要的not holding the head in that case

+0

考慮使用術語'binding'而不是'var',因爲'var'是Clojure中的一種特定類型的數據,它是可變的,並且幾乎總是全局的。 – noisesmith 2014-10-12 21:31:03

+0

謝謝!改變了它。 – DanLebrero 2014-10-12 22:23:50

+0

所以這個解決方案的關鍵是使用該文件封裝讀取文件內的文件?這樣,當函數返回時,它知道釋放底層序列?我一直在相同的'let'範圍內聲明文件序列並將其作爲參數傳遞給所有函數,但這似乎是我的主要設計缺陷。 – user1559027 2014-10-13 23:23:33