简体   繁体   English

如何从文件中读取内容并将其存储在 clojure 的哈希映射中?

[英]How to read contents from a file and store it in a hash-map in clojure?

I got a small problem in clojure.我在 clojure 中遇到了一个小问题。 I am new to this programming environment and need a little help.我是这个编程环境的新手,需要一点帮助。 I have got a text file in this format:我有一个这种格式的文本文件:

1|John Smith|123 Here Street|456-4567
2|Sue Jones|43 Rose Court Street|345-7867
3|Fan Yuhong|165 Happy Lane|345-4533

I want to parse each line in file and want to store data in hashmap in this way:我想解析文件中的每一行,并希望以这种方式将数据存储在 hashmap 中:

{ 1 : [John Smith, 123 here street, 456-4567], 2 : ... }

Here is my code till now but I have not got any success.到目前为止,这是我的代码,但我没有取得任何成功。

(defn readcustfile[]
  (def cust-file (clojure.string/split-lines (slurp "cust.txt"))) 

  (doseq [line cust-file]
    (def cust-id (nth (clojure.string/split line #"\|") 0))
    (def cust-name (str (nth (clojure.string/split line #"\|") 1)))
    (def cust-add (str (nth (clojure.string/split line #"\|") 2)))
    (def cust-phone (str (nth (clojure.string/split line #"\|") 3)))
    (def cust-data (str cust-name "," cust-add "," cust-phone))
    (def cust (map (fn [[id name add phone]]
                     (list (Integer/parseInt cust-id)
                           (hash-map :name cust-name
                                     :add cust-add
                                     :phone cust-phone))
    )
  )
(readcustfile)

what i would propose, is to read file line by line transducing it into resulting map in one pass:我建议的是逐行读取文件,一次将其转换为生成的 map:

(require '[clojure.java.io :refer [reader]]
         '[clojure.string :as cs]
         '[clojure.edn :as edn])

(with-open [rdr (reader "data.csv")]
  (into {}
        (map (comp (juxt (comp edn/read-string first) rest)
                   #(cs/split % #"\|")))
        (line-seq rdr)))

;;=> {1 ("John Smith" "123 Here Street" "456-4567"),
;;    2 ("Sue Jones" "43 Rose Court Street" "345-7867"),
;;    3 ("Fan Yuhong" "165 Happy Lane" "345-4533")}

notice, you don't have to read the whole file into memory, rather you use with-open reader + line seq .注意,您不必将整个文件读入 memory,而是使用with-open reader + line seq

notice also, the form of into + map (the transducer) is used instead of simple map then into {} or for , to avoid intermediate collection creation.另请注意,使用into + map (传感器)的形式代替简单的map然后into {}for ,以避免创建中间集合。

You should use a library to read CSV data.您应该使用库来读取 CSV 数据。 Here is another one .这是另一个

Here is an example:这是一个例子:

(ns tst.demo.core
  (:use tupelo.core tupelo.test)
  (:require
    [tupelo.csv :as csv]
    ))

; use (slurp <filename>) to read data into a string
(def data-str
  "id|name|address|phone
   1|John Smith|123 Here Street|456-4567
   2|Sue Jones|43 Rose Court Street|345-7867
   3|Fan Yuhong|165 Happy Lane|345-4533 ")

Note that I added a header line to describe the fields of each CSV record.请注意,我添加了一条 header 行来描述每个 CSV 记录的字段。 Unit tests show the result:单元测试显示结果:

(dotest
  (let [entity-maps (csv/parse->entities data-str :delimiter \|)
        grouped     (group-by :id entity-maps)]

    (is= entity-maps
      [{:id      "1",
        :name    "John Smith",
        :address "123 Here Street",
        :phone   "456-4567"}
       {:id      "2",
        :name    "Sue Jones",
        :address "43 Rose Court Street",
        :phone   "345-7867"}
       {:id      "3",
        :name    "Fan Yuhong",
        :address "165 Happy Lane",
        :phone   "345-4533"}])

    (is= grouped
      {"1"
       [{:id      "1",
         :name    "John Smith",
         :address "123 Here Street",
         :phone   "456-4567"}],
       "2"
       [{:id      "2",
         :name    "Sue Jones",
         :address "43 Rose Court Street",
         :phone   "345-7867"}],
       "3"
       [{:id      "3",
         :name    "Fan Yuhong",
         :address "165 Happy Lane",
         :phone   "345-4533"}]})))

Be sure to see this list of documentation , especially the Clojure CheatSheet.请务必查看此文档列表,尤其是 Clojure CheatSheet。

(def cust-file ["1|John Smith|123 Here Street|456-4567"
                "2|Sue Jones|43 Rose Court Street|345-7867"
                "3|Fan Yuhong|165 Happy Lane|345-4533"])

(into {}                      ;; construc new hash map from coll
                              ;; (into {} ["key" "data"]) => {"key" "data"}
      (for [line cust-file    ;; `for` instead of `doseq`
                              ;; (`doseq` will return nil, but `for` - results of iteration)
            :let [[id & data] ;; shortend `let` alias, use desctructjion to get `id` and rest as `data`
                  (clojure.string/split line #"\|")]]
        [(Integer/parseInt id) data])) ;; return pair [id [name add phone]] for every line

;; => {1 ("John Smith" "123 Here Street" "456-4567"),
;;     2 ("Sue Jones" "43 Rose Court Street" "345-7867"),
;;     3 ("Fan Yuhong" "165 Happy Lane" "345-4533")}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM