6

我正在编写一段需要读取包含数据的文本文件的代码。文本文件格式为:

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

接下来,我尝试 slurp 文件,但情况更糟:

=> (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 中却让我很生气。

4

2 回答 2

7

将其拆分为一系列行:

(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

于 2012-07-15T19:05:34.613 回答
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"))
于 2012-07-15T20:36:55.167 回答