在clojure中恢复数据

时间:2018-06-02 22:01:37

标签: clojure functional-programming

我有三个文本文件http://paste.debian.net/plain/1027720。由于第三个文件采用以下格式

Third File

salesID | custID | prodID | itemCount
1|1|1|3
2|2|2|3

我想显示表格,以便客户名称和产品说明中的prodID替换custID, 如下: 1:[“约翰”“鞋子”“3”] 我到现在所做的是:

(def data (slurp "cust.txt"))
(->> (for [line (clojure.string/split data #"[ ]*[\r\n]+[ ]*")]
       (-> line (clojure.string/split #"\|") rest vec))
     (map vector (rest (range))))

我如何相应地检索和映射值?

修改

"demo_1.txt"
content id|name|address|phone-number
1|John|123 Street|456-4567
2|Smith|123 Here Street|456-4567

"demo_2.txt"
prodID | item | Cost
1|shoes|14.96
2|milk|1.98

1 个答案:

答案 0 :(得分:1)

此数据的处理类似于我处理CSV文件的方式。我喜欢将问题分解为行向量和向量映射的函数,使用第一行作为每个行的标题。

(defn line->vec [s]
  (s/split s #"\|"))

(defn vec->map [desc row]
  (into {}
    (map vector desc row))) ; Map accepts multiple collections

(defn file->maps [filename]
  ; Destructuring here, for easy capturing of header row
  (let [[desc & lines] (->> (slurp filename)
                            (s/split-lines)
                            (map line->vec))
        desc-keys (map keyword desc)]
    (for [line lines]
      (vec->map desc-keys line))))

对于您的演示文件,您可以使用group-by生成地图,有点像索引(我手动修复了标题格式,但您想要使用实用程序fn):

(group-by :content-id (file->maps "demo_1.txt"))

{"1" [{:address "123 Street",
       :phone-number "456-4567",
       :name "John",
       :content-id "1"}],
 "2" [{:address "123 Here Street",
       :phone-number "456-4567",
       :name "Smith",
       :content-id "2"}]}

(group-by :prodID (file->maps "demo_2.txt"))

{"1" [{:item "shoes", :prodID "1", :cost "14.96"}],
 "2" [{:item "milk", :prodID "2", :cost "1.98"}]}

然后用其索引值替换每列:

(defn replace-value [index idx-key m k]
  (update m k #(get-in index [% 0 idx-key])))

(defn -main [& args]
  (let [customers (group-by :content-id (file->maps "demo1.txt"))
        products (group-by :prodID (file->maps "demo2.txt"))]
    ; Use customers and products to replace some data
    (->> (file->maps "demo_3.txt")
         (map #(replace-value customers :name % :content-id))
         (map #(replace-value products :item % :prodID)))))

结果:

({:prodID "shoes", :content-id "John", :salesID "1", :itemCount "3"}
 {:prodID "milk", :content-id "Smith", :salesID "2", :itemCount "3"})

然后将这些地图转换回您想要的格式应该很简单。