简体   繁体   English

在Clojure中获取PersistentArrayMap的键

[英]Get key of PersistentArrayMap in clojure

My question could be a little bit easy to answer but I've just started to learn clojure and I have no idea of how to do this. 我的问题可能有点容易回答,但是我才刚刚开始学习Clojure,我不知道该怎么做。

I have a JSON file that I have read and parsed. 我有一个已读取和解析的JSON文件。 Now I have to get each element of this JSON and treat then according with the type. 现在,我必须获取此JSON的每个元素,然后根据类型进行处理。 For example, I have the JSON: 例如,我有JSON:

{
  "foo": {
    "id": 1,
    "name": "foo1"
  },
  "bar": {
    "id": 1,
    "name": "bar1"
  },
  "foo": {
    "id": 2,
    "name": "foo2"
  },
  "bar": {
    "id": 2,
    "name": "bar2"
  }
}

So, I want to make a function that iterate on every element of my JSON and then call another function with multiples declarations for each element type of my JSON. 因此,我想创建一个对JSON的每个元素进行迭代的函数,然后为JSON的每个元素类型调用具有多个声明的另一个函数。

The problem is that I don't know how I can get the JSON element type... Can someone help me? 问题是我不知道如何获取JSON元素类型...有人可以帮我吗?

You can get all key-value pairs of a map by treating it as a Clojure sequence. 通过将其视为Clojure序列,可以获取映射的所有键值对。 Then it behaves as a sequence of two-element vectors, a sequence of MapEntry elements to be more precise. 然后,它表现为一个包含两个元素的向量的序列,更精确地说是一个MapEntry元素的序列。 When you call first on a MapEntry you will get the key. 当您firstMapEntry上致电时,您将获得密钥。

So (first (seq {:a 1})) returns [:a 1] and (first [:a 1]) returns :a , the key. 因此, (first (seq {:a 1}))返回[:a 1](first [:a 1])返回:a The call to seq in this example is not needed, but is only there to make the example more explicit. 在此示例中,不需要对seq进行调用,但这仅是为了使示例更明确。

You could then write a case expression to do things according to the key. 然后,您可以编写一个case表达式以根据键执行操作。 To make it more extensible you could use multimethods. 为了使其更具扩展性,您可以使用多种方法。

(def json-str "{\n  \"foo\": {\n    \"id\": 1,\n    \"name\": \"foo1\"\n  },\n  \"bar\": {\n    \"id\": 1,\n    \"name\": \"bar1\"\n  },\n  \"foo\": {\n    \"id\": 2,\n    \"name\": \"foo2\"\n  },\n  \"bar\": {\n    \"id\": 2,\n    \"name\": \"bar2\"\n  }\n}")

(def parsed (cheshire.core/parse-string json-str true))
;; {:foo {:id 2, :name "foo2"}, :bar {:id 2, :name "bar2"}}

;; handle with case:

(defn handle-data
  [data]
  (doseq [[k v] data]
    (case k
      :foo (println "this is a foo!" v)
      :bar (println "this is a bar!" v)
      (throw (ex-info (str "Did not recognize key "
                           key)
                      {:key k
                       :map v})))))

;; handle with multimethods:

(defmulti do-thing-depending-on-key first)

(defmethod do-thing-depending-on-key :foo [[k v]]
  (println "this is a foo!" v))

(defmethod do-thing-depending-on-key :bar [[k v]]
  (println "this is a bar!" k))

(defmethod do-thing-depending-on-key :default [[k v]]
  (throw (ex-info (str "Did not recognize key "
                       key)
                  {:key k
                   :map v})))

(run! do-thing-depending-on-key parsed)
;; this is a foo! {:id 2, :name foo2}
;; this is a bar! {:id 2, :name bar2}
;; => nil

(run! do-thing-depending-on-key {:unknown {:id 3 :name "Unknown"}})
;; => 
;; clojure.lang.ExceptionInfo:
;; Did not recognize key :unknown {:key :unknown, :map {:id 3, :name "Unknown"}}

Multimethods might be overkill for something this simple. 对于这种简单的事情,多方法可能会显得过大。 I'd just use cond : 我只是用cond

(ns tst.demo.core
  (:require
    [cheshire.core :as cheshire]
    [clojure.java.io :as io] ))

  (let [json-str (slurp (io/resource "data.json"))
        edn-data (cheshire/parse-string json-str true) ; need `true` to emit keywords
        ]
    (doseq [[type id-name-map] edn-data]
      (cond
        (= type :foo) (println :foo-proc id-name-map)
        (= type :bar) (println :bar-proc id-name-map)
        :else         (println :other-proc id-name-map) )))

with results: 结果:

:foo-proc {:id 2, :name foo2}
:bar-proc {:id 2, :name bar2}

which requires the following in project.clj : project.clj需要以下内容:

  :dependencies [
    [cheshire "5.8.0"]
      ....

and where your data is in resources/data.json : 以及您的数据在resources/data.json

~/expr/demo > cat resources/data.json 
{
  "foo": {
    "id": 1,
    "name": "foo1"
  },
  "bar": {
    "id": 1,
    "name": "bar1"
  },  ....

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

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