2012-07-15 45 views
6

我正在寫一段代碼,需要讀取含有數據的文本文件。該文本文件的格式爲:如何使用Clojure讀取含有測試數據的文件?

name 1 4 
name 2 4 5 
name 3 1 9 

我想在形式[:name Sarah :weight 1 cost :4]創建地圖的載體。

當我嘗試使用line-seq閱讀器讀取文件時,它將每行讀取爲一個項目,因此分區不正確。請參閱下面的代碼:

(let [file-text (line-seq (reader "C://Drugs/myproject/src/myproject/data.txt")) 
         new-test-items (vec (map #(apply struct item %) (partition 3 file-text)))] 
    (println file-text) 
    (println new-test-items)) 


(sarah 1 1 jason 4 5 nila 3 2 jonas 5 6 judy 8 15 denny 9 14 lis 2 2 ) 
[{:name sarah 1 1, :weight jason 4 5, :value nila 3 2 } {:name jonas 5 6, :weight judy 8 15, :value denny 9 14}] 

然後我試圖拿1分區,但仍然是結構不正確。

=> (let [file-text (line-seq (reader "C://Drugs/myproject/src/myproject/data.txt")) 
           new-test-items (vec (map #(apply struct item %) (partition 1 file-text)))] 
       (println file-text) 
       (println new-test-items)) 
(sarah 1 1 jason 4 5 nila 3 2 jonas 5 6 judy 8 15 denny 9 14 lis 2 2 ) 
[{:name sarah 1 1, :weight nil, :value nil} {:name jason 4 5, :weight nil, :value nil} {:name nila 3 2 , :weight nil, :value nil} {:name jonas 5 6, :weight nil, :value nil} {:name judy 8 15, :weight nil, :value nil} {:name denny 9 14, :weight nil, :value nil} {:name lis 2 2, :weight nil, :value nil} {:name , :weight nil, :value nil}] 
nil 

下一個我試圖發出聲音文件,但更糟糕的是:

=> (let [slurp-input (slurp "C://Drugs/myproject/src/myproject/data.txt") 
      part-items (partition 3 slurp-input) 
      mapping (vec (map #(apply struct item %) part-items))] 
      (println slurp-input) 
      (println part-items) 
      (println mapping)) 
sarah 1 1 
jason 4 5 
nila 3 2 
jonas 5 6 
judy 8 15 
denny 9 14 
lis 2 2 

((s a r) (a h ) (1 1) (

請幫幫忙!這在Java中看起來像是一件容易的事情,但卻讓我在Clojure中遇難。

回答

6

將它分成線的序列:

(line-seq (reader "/tmp/data")) 

分裂它們中的每成單詞的一個序列

(map #(split % #" ") data) 

使一個函數,它有一個數據的矢量和其轉換爲帶正確鑰匙的地圖

(fn [[name weight cost]] 
    (hash-map :name name 
      :weight (Integer/parseInt weight) 
      :cost (Integer/parseInt cost))) 

然後將它們一起築巢回去

(map (fn [[name weight cost]] 
     (hash-map :name name 
       :weight (Integer/parseInt weight) 
       :cost (Integer/parseInt cost))) 
    (map #(split % #" ") (line-seq (reader "/tmp/data")))) 

({:weight 1, :name "name", :cost 4} 
{:weight 2, :name "name", :cost 4} 
{:weight 3, :name "name", :cost 1}) 

你也可以讓這個更緊湊通過使用zip-map

+1

,因爲這是懶惰的,就看你要記住關閉時,你不會從中讀取任何數據文件。 (我經常發現我的自我包裝序列在一個空的close-when-empty懶讀者中。 – 2012-07-15 19:24:28

+0

split來自clojure.string,讀者來自clojure.java.io – 2012-07-15 19:25:19

+0

Arthur非常感謝你! (散列映射:名稱名稱 :權重(Integer/parseInt權重) :成本(整數/ parseInt成本))),則會出現以下錯誤:=>(map(fn [[name weight cost]] (map#(split%#「」)(line-seq(reader「C://Drugs/myproject/src/myproject/data.txt」)))) CompilerException java.lang.RuntimeException:無法解析符號:在這種情況下拆分,編譯:(NO_SOURCE_PATH:5) – user1525748 2012-07-15 19:25:39

3

你正在嘗試做的一切都在一個地方沒有測試中間結果。相反,Clojure建議將任務分解爲若干子任務 - 這使得代碼更靈活靈活可測試。下面是你的任務的代碼(我假設在文件中的記錄形容人):

(defn read-lines [filename] 
    (with-open [rdr (clojure.java.io/reader filename)] 
    (doall (line-seq rdr)))) 

(defn make-person [s] 
    (reduce conj (map hash-map [:name :weight :value] (.split s " ")))) 

(map make-person (read-lines "/path/to/file"))