Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/clojure/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/magento/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Dictionary 使用clojure将多行读取到记录中_Dictionary_Clojure_Set - Fatal编程技术网

Dictionary 使用clojure将多行读取到记录中

Dictionary 使用clojure将多行读取到记录中,dictionary,clojure,set,Dictionary,Clojure,Set,我正在学习clojure,我想把一条横跨多行的记录读入一组地图。实际上,该文件的内容是从ami映像/快照/卷和实例列表上的AWS控制台复制和粘贴的 生成的文本文件的内容如下所示:- Record 1 Field Value 1 Record 1 Field Value 2 Record 1 Field Value 3 Record 2 Field Value 1 Record 2 Field Value 2 Record 2 Field Value 3 我写的是 (defn read-file

我正在学习clojure,我想把一条横跨多行的记录读入一组地图。实际上,该文件的内容是从ami映像/快照/卷和实例列表上的AWS控制台复制和粘贴的

生成的文本文件的内容如下所示:-

Record 1 Field Value 1
Record 1 Field Value 2
Record 1 Field Value 3
Record 2 Field Value 1
Record 2 Field Value 2
Record 2 Field Value 3
我写的是

(defn read-file [file]
    (letfn [(readit [rdr]
        (lazy-seq
            (if-let [ami-name (.readLine rdr) ]
                (cons ami-name (readit rdr ))
                (do (.close rdr) nil))))]
        (filter #(not (clojure.string/blank? %)) (readit (clojure.java.io/reader file)))))
它工作得很好,可以将所有内容添加到列表中。但我的最终目标是将三个相似的文件读入三组地图,然后将它们连接在一起,以创建有意义的内容,找出具有集差异的过时记录。我想我可以根据公共密钥字段加入三组记录。问题是我不知道如何将文本文件读入一组地图。这三个文件的格式类似,如下所示:-

文件1

*Field Count (N)*
Field Label 1
Field Label 2
..
Field Label N
Record 1 Field Value 1
Record 1 Field Value 2
Record 1 Field Value N
Record 2 Field Value 1
Record 2 Field Value 2
..
Record 2 Field Value N
地图的结果列表如下所示:-

(def instance-list
    #{{Field Label 1: Record 1 Field Value 1 Field Label 2: Record 1 Field Value 2 Record 1 Field Label N: Field Value N}
    {Field Label 1: Record 2 Field Value 1 Field Label 2: Record 2 Field Value 2 Record 2 Field Label N: Field Value N}
    {Field Label 1: Record N Field Value 1 Field Label 2: Record N Field Value 2 Record N Field Label N: Field Value N}})
样本数据如下:-

3
Name
Instance id
volume id
My own instance 1
Ins-123456
Vol-234567
*Blank line*
My own instance 2
Ins-123457
Vol-234568
*Blank line*
我的想法是将第一行作为字段计数读取,然后将行分成两组,一组作为标题,另一组作为数据:-

user=> (defn parse-int [s]
  #_=> (Integer. (re-find  #"\d+" s )))

#'user/parse-int
user=> (split-at (parse-int (first (read-file "test.txt"))) (rest (read-file "test.txt")))
[(“名称”“实例id”“卷id”)(“我自己的实例1”“Ins-123456”“Vol-234567”“我自己的实例2”“Ins-123457”“Vol-234568”)]

我是否可以将这两个列表转换为一组地图


有人能帮忙吗?

这里有一个尝试,它只是一个快乐的案例,没有尝试先检查文件是否具有预期的结构:

(defn read-file [file]
  (with-open[rdr (clojure.java.io/reader file)]
    (let[lines (line-seq rdr)
         num-fields (Long/valueOf (first lines))
         fields (->> lines (drop 1) (take num-fields))
         block-size (inc num-fields)
         records (->> lines
                      (drop block-size) 
                      (partition block-size) 
                      (map (partial zipmap fields)))]
      (into #{} records))))

;;Returns #{{"volume id" "Vol-2345", "Instance id" "Ins-123457", "Name" "My own instance 2"} 
;;          {"volume id" "Vol-23456", "Instance id" "Ins-12345", "Name" "My own instance 1"}} 
请注意,使用
line seq
与您的
readit
fn执行的操作大致相同。从line seq开始,有几个基本步骤:

  • 获取字段数
  • 取这么多行并将它们存储为字段名。如果需要,您可以将
    关键字
    映射到此处,并将它们的数据类型从字符串更改为字符串
  • 删除字段规范,然后将行seq划分为与单个记录相对应的“块”。我添加1是为了获取您的
    *空行*
    s,但它们没有被使用
  • 使用
    zipmap
    构建我们想要的映射。这是一个非常有用的函数,它接受一系列键和一系列值,并将它们粘在一个映射中。我们总是希望使用相同的键(我们的
    字段
    )因此,我们可以部分地将ZIPMAP作为参数使用,然后在值的SEQS上映射它。它将不使用没有相应键的值,这就是我们如何除去空行。
  • 使用
    into
    将地图收集到一个集合中

  • 使用初始的
    readfile()
    函数构建记录序列。我选择
    关键字
    -ise字段名和记录ID:

    (defn record-seq [file]
      (let [data      (read-file file)
            nb-fields (Integer/parseInt (first data))
            fields    (map #(keyword (str/replace % #"\s+" "-"))
                           (take nb-fields (rest data)))
            values    (filter (complement str/blank?)
                              (drop (inc nb-fields) data))
            rec-ids   (map #(keyword (str "rec-" %))
                           (range))]
        (map #(vector %1 (zipmap fields %2))
             rec-ids
             (partition nb-fields values))))
    
    user> (pprint (record-seq "./ami.log"))
    ([:rec-0
      {:volume-id "Vol-23456",
       :Instance-id "Ins-12345",
       :Name "My own instance 1"}]
     [:rec-1
      {:volume-id "Vol-2345",
       :Instance-id "Ins-123457",
       :Name "My own instance 2"}]
     [:rec-2
      {:volume-id "Vol-9876",
       :Instance-id "Ins-123987",
       :Name "My own instance 3"}])
    
    建立一个
    记录集
    只是一个简单的问题

    (into #{} (map second (record-seq "./ami.log"))) 
    

    字段标签1
    是一个字符串,即
    字段标签1
    ?是否希望
    将1个字段值1
    记录为一个
    字符串
    还是两个
    字符串
    或一个映射,例如
    {:记录1:字段值1}
    ?我前面的问题更多的是关于所有这些空白:这是您的实际数据格式吗?您能发布一个正确的数据样本吗?编辑问题以提供样本数据并重新格式化文件框架。更正了问题,因为我需要一组映射而不是映射列表,这样我就可以执行集合操作,如join,联合、差异等。解决方案非常简洁。而我的缺点是,空行的编号是2而不是1,此解决方案会将这些空行作为字段混合在一起,这将填充创建的记录。无论如何,非常感谢您的帮助。