How to read test data file using Clojure?

I am writing a piece of code to be read in a text data file. The text file is in the format:

name 1 4 name 2 4 5 name 3 1 9 

I am trying to create a map vector in the form [:name Sarah :weight 1 cost :4] .

When I try to read a file using the -qq line reader, it reads each line as an element, so the section is incorrect. See below:

 (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}] 

Then I tried to just take 1 section, but still the structure is wrong.

 => (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 

Then I tried to rip out the file, but this is worse:

 => (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 ((sar) (ah ) (1 1) ( 

Please, help! It seems like such an easy thing in Java, but it kills me in Clojure.

+6
source share
2 answers

divide it into a sequence of lines:

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

break each of them into a sequence of words

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

make a function that takes a vector with one data and turns it into a map with the right keys

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

then put them back together

 (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}) 

you can also make it more compact using zip-map

+6
source

You are trying to do everything in one place without testing intermediate results. Instead, Clojure recommends splitting the task into several subtasks - this makes the code much more flexible and testable . Here's the code for your task (I assume the entries in the file describe people):

 (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")) 
+3
source

Source: https://habr.com/ru/post/920537/


All Articles