【问题标题】:How to read json file into Clojure defrecord (to be searched later)如何将 json 文件读入 Clojure defrecord (稍后搜索)
【发布时间】:2013-03-27 13:29:38
【问题描述】:

我在 Clojure REPL 中创建了一个 defrecord:

user=> (defrecord Data [column1 column2 column3])
user.Data

如何通过读取 .json 文件自动向该记录添加数据? defrecord 中的每一列都与 json 数据中的一个键完全对应。如果文件包含一条记录,它看起来类似于:

[
  {
    "column1" : "value1"
    "column2" : "value2"
    "column3" : "value3"
  }
]

但是文件中有成千上万条这样的记录。

我可以像这样 slurp 文件的内容:

(json/read-json (slurp "path/to/file.json")))

read-json 函数的依赖项被添加到 project.clj 文件中,该文件位于我从命令行运行 lein repl 的目录中::dependencies [org.clojure/data.json "0.2.1"]

我希望能够使用 Clojure 函数搜索记录的值,这样我传递给搜索函数的值介于单个记录的 column1 和 column2 值之间(即 nth-record.column1.value 查询 nth-record.column2.value em>)。找到匹配记录后,我想返回同一记录中另一列的值 (nth-record.column3.value)。第 1 列和第 2 列的值将是唯一的,表示不重叠的值范围。 column3 的值不是唯一的。

这似乎是一项相当微不足道的任务,但我不知道如何使用 Clojure 文档或我在网上找到的示例来完成它。对我而言,记录在 Clojure 内部如何存储并不重要,只要我可以搜索它们并返回同一记录中相关字段的值即可。

【问题讨论】:

    标签: json clojure


    【解决方案1】:

    使用data.json 包:

    (require '[clojure.data.json :as json])
    

    将值读入内存:

    (def all-records (json/read-str (slurp "path/to/file.json")
                    :key-fn keyword))
    ;; ==> [ { :column1 "value1", :column2 "value2", :column3 "value3" }, ...]
    

    查找匹配记录:

    (def query "some-value")
    (def matching (filter #(and (< (:column1 %) query) (< query (:column2 %))) all-records))
    

    获取第 3 列:

    (map :column3 matching)
    

    将它们收集在一起(并使其更灵活):

    (defn find-matching [select-fn result-fn records]
       (map result-fn (filter select-fn records)))
    
    (defn select-within [rec query]
      (and (< (:column1 rec) query) (< query (:column2 rec))))
    
    (find-matching #(select-within % "some-value") :column3 all-records)
    

    【讨论】:

    • ffriend,非常感谢您的帮助。我仍然在使用查找匹配功能时遇到了一些问题。 repl 抱怨我没有向函数传递足够的参数。是否应该在 :column3 之后将所有记录作为第三个参数传递?
    • @ChrisDevo:是的,抱歉,手头没有 REPL。我已经更新了我的代码。
    • 我的地图中的值存储为字符串。要进行数值比较,我必须将(:column1 rec) 修改为(bigint (:column1 rec)),否则我会得到ClassCastException java.lang.String cannot be cast to java.lang.Number clojure.lang.Numbers.lt (Numbers.java:219)
    【解决方案2】:
    1. 应该使用 cheshire 来提高速度。
    2. 如果您的查询变得足够复杂,请考虑使用 lucene,clojure 有一个很好的包装器。

    我认为您认为记录在某种程度上比地图更适合于此,据我所知,您没有使用任何使记录变得特别的功能,例如多态性。可能有办法让柴郡吐出唱片,但我不会打扰。

    【讨论】:

    • 谢谢,gtrak。我也不确定我是否需要defrecords。我仍然习惯于代码就是数据的功能范式,反之亦然。
    猜你喜欢
    • 1970-01-01
    • 2020-08-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多