2013-06-23 31 views
4

我正在嘗試讀取大型文本文件並計算出現特定錯誤。 例如,對於下面的示例文本clojure讀取大型文本文件並對發生次數進行計數

something 
bla 
error123 
foo 
test 
error123 
line 
junk 
error55 
more 
stuff 

我想結束了(真的不關心什麼數據結構,雖然我想到一個地圖)

error123 - 2 
error55 - 1 

這裏是我有什麼試過到目前爲止

(require '[clojure.java.io :as io]) 

(defn find-error [line] 
    (if (re-find #"error" line)  
     line)) 


(defn read-big-file [func, filename] 
(with-open [rdr (io/reader filename)] 
    (doall (map func (line-seq rdr))))) 

調用它像這樣

(read-big-file find-error "sample.txt") 

回報:

(nil nil "error123" nil nil "error123" nil nil "error55" nil nil) 

接下來,我試圖刪除零值和組類似物品

(group-by identity (remove #(= nil %) (read-big-file find-error "sample.txt"))) 

返回

{"error123" ["error123" "error123"], "error55" ["error55"]} 

這是越來越接近期望的輸出,儘管它可能不高效。我現在怎樣才能得到這些數字?另外,作爲clojure和函數式編程的新手,我將不勝感激任何有關如何改進這一點的建議。 謝謝!

回答

6

我想你可能會尋找頻功能:

user=> (doc frequencies) 
------------------------- 
clojure.core/frequencies 
([coll]) 
    Returns a map from distinct items in coll to the number of times 
    they appear. 
nil 

所以,這應該給你你想要的東西:

(frequencies (remove nil? (read-big-file find-error "sample.txt"))) 
;;=> {"error123" 2, "error55" 1} 

如果你的文本文件,是真正的大,但是,我建議在line-seq內聯上執行此操作,以確保您不會耗盡內存。這樣,您也可以使用filter而不是mapremove

(defn count-lines [pred, filename] 
    (with-open [rdr (io/reader filename)] 
    (frequencies (filter pred (line-seq rdr))))) 

(defn is-error-line? [line] 
    (re-find #"error" line)) 

(count-lines is-error-line? "sample.txt") 
;; => {"error123" 2, "error55" 1} 
+0

謝謝,這就是我一直在尋找的! –

相關問題