如何在 Clojure 中将文件中的数据读取到哈希映射或其他数据结构中?

如何解决如何在 Clojure 中将文件中的数据读取到哈希映射或其他数据结构中?

不太确定从哪里开始。 我有一个大数据文件,其中包含与某个事物相关的不同值(即第 1 列中的数据是小时),该文件有 15 列宽。该文件不包含任何列标题,只是数字数据。

我需要将这些数据读入一种数据类型,例如哈希映射,这样我就可以对它进行排序并使用诸如包含之类的东西来查询数据?以及执行计算。

我不确定如何执行此操作,因为我是 Clojure 的新手,我们将不胜感激。

我的文件是一个 txt 文件(另存为 mydata.txt),结构如下:

  1 23 25 -9  -0 1 1
  2 23 25 10 1 2 3

到目前为止我的代码是:

(def filetoanalyse (slurp "mydata.txt"))
(zipmap [:num1 :num2 :num3 :num4 :num5 :num6 :num7] filetoanalyse)

它似乎将整个文件与当前的 :num1 相关联。

解决方法

您遇到的问题是 slurp 将文件作为字符串读入。当你在它上面使用 zipmap 时,它使用字符串中的字符作为映射中的值,导致这种混乱:

(zipmap [:num1 :num2 :num3 :num4 :num5 :num6 :num7] (slurp "mydata.txt"))
;;=> {:num1 \space,:num2 \space,:num3 \1,:num4 \space,:num5 \2,:num6 \3,:num7 \space}

最简单的方法是逐行遍历文件,将其拆分为您想要的值。注意这里的 vec,它强制(惰性)for 的结果,确保我们在 with-open 关闭读取器之前处理整个文件。

(with-open [reader (clojure.java.io/reader "mydata.txt")]
  (vec (for [line (line-seq reader)]    ; iterate over each line
         (->> (clojure.string/split line #"\s+") ; split it by whitespace
              (remove empty?)           ; remove any empty entries
              (map #(Long/parseLong %)) ; convert into Longs (change if another format is more suitable)
              (zipmap [:num1 :num2 :num3 :num4 :num5 :num6 :num7]))))) ; turn into a map
,

这里有一个函数,你可以用它来做你想要的:

(defn map-from-file [field-re column-names filename]
  (let [ lines  (re-seq #"[^\r\n]+" (slurp filename)) ]
    (map #(zipmap column-names (re-seq field-re %)) lines)))

您必须提供三个参数:

  1. 用于分隔每行中的字段的正则表达式。对于您显示的数据,这可以是 #"[^ ]+",或者基本上任何不是空白的东西都是该字段的一部分。如果您有简单的逗号分隔值,没有复杂性,例如数据或引用字段中的嵌入逗号,则 #"[^,]+" 之类的东西会起作用。或者,如果您只想提取数字字符,则可以使用更复杂的内容,例如 `#"[-0-9]+"。

  2. 要分配的列名集合。

  3. 文件名。

因此,如果您在问题中显示的数据存储为 test3.dat,则您可以将上述函数调用为

(map-from-file #"[^ ]+" [:c1 :c2 :c3 :c4 :c5 :c6 :c7] "/some-path/test3.dat")

它会返回

({:c1 "1",:c2 "23",:c3 "25",:c4 "-9",:c5 "-0",:c6 "1",:c7 "1"} {:c1 "2",:c4 "10",:c5 "1",:c6 "2",:c7 "3"})

或者换句话说,您会返回一系列映射,这些映射按您提供的列名称映射值。如果您更喜欢将数据放在向量中,可以使用

(into [] (map-from-file #"[^ ]+" [:c1 :c2 :c3 :c4 :c5 :c6 :c7] "/some-path/test3.dat"))
,

主要答案

Slurp 会将文件内容作为文本字符串返回,但您的代码似乎假定此文件已被解析为数字数组。事实并非如此。您仍然可以使用 slurp,但您必须自己解析文件。您可以通过首先使用 split-lines 按行分隔符拆分文件字符串来解析它。如果我们用方括号将向量包围起来,每一行都是有效的 Clojure 语法,如果我们这样做,我们可以使用 edn/read-string 将其解析为向量。我们使用 map 来解析文件的每一行。以下代码将完成这项工作,并使用 ->> 宏来保持代码可读性:

(require '[clojure.string :as cljstr])
(require '[clojure.edn :as edn])

(->> "/tmp/mydata.txt"
     slurp
     cljstr/split-lines
     (map #(zipmap
            [:num1 :num2 :num3 :num4 :num5 :num6 :num7]
            (edn/read-string (str "[" % "]")))))
;; => ({:num1 1,:num2 23,:num3 25,:num4 -9,:num5 0,:num6 1,:num7 1} {:num1 2,:num4 10,:num5 1,:num6 2,:num7 3})

扩展/变体

如果有包含其他元素数量的行,您可能只想保留那些包含七个元素的行,使用 filter。映射和过滤可以组成一个 transducer,我们将其作为参数传递给 into

(let [columns [:num1 :num2 :num3 :num4 :num5 :num6 :num7]
      n (count columns)]
  (->> "/tmp/mydata.txt"
       slurp
       cljstr/split-lines
       (into [] (comp (map #(zipmap
                             columns
                             (edn/read-string (str "[" % "]"))))
                      (filter #(= n (count %)))))))
;; => [{:num1 1,:num7 3}]

如果您希望解析更复杂的文件或真的想终止/过度设计它,您可以使用 spec:

(require '[clojure.spec.alpha :as spec])

(->> "/tmp/mydata.txt"
     slurp
     cljstr/split-lines
     (map #(edn/read-string (str "[" % "]")))
     (spec/conform (spec/coll-of (spec/cat :num1 number?
                                           :num2 number?
                                           :num3 number?
                                           :num4 number?
                                           :num5 number?
                                           :num6 number?
                                           :num7 number?))))
;; => ({:num1 1,:num7 3})

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 <select id="xxx"> SELECT di.id, di.name, di.work_type, di.updated... <where> <if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 <property name="dynamic.classpath" value="tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams['font.sans-serif'] = ['SimHei'] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -> systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping("/hires") public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate<String
使用vite构建项目报错 C:\Users\ychen\work>npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-