简体   繁体   English

Clojure:尝试将哈希映射转换为字符串

[英]Clojure: Trying to convert a hash-map into a string

I am pretty new to Clojure and still trying to grasp the fundamentals.我是 Clojure 的新手,仍在努力掌握基础知识。 While experimenting, I had the following problem.在试验时,我遇到了以下问题。 I tried to make a nested map and convert this into a JSON Object without the use of an external library, but keep running into a wall.我试图在不使用外部库的情况下制作一个嵌套的 map 并将其转换为 JSON Object,但一直碰壁。 I was wondering if someone could guide / help me to get on the right track.我想知道是否有人可以指导/帮助我走上正轨。

I want to thank you in advance for taking the time to read this and help me out.我想提前感谢您花时间阅读本文并帮助我。

I have the following hash-map in Clojure:我在 Clojure 中有以下哈希映射:

; Creating Hashmap
(def hashmap
  [
   { :Mineral-1 {
            :Mineral-name       {:value "Gold"}
            :Color              {:value "Golden"}
            :Weight             {:value 2324.23}
            :Count              {:value 203}
            :Price              {:value 20320.49}
            :DeliveryContainers {:value-1 {:value 1}
                                 :value-2 {:value 2}
                                 :value-3 {:value 3}}
            :Sold               {:value true}
            }
    }
   { :Mineral-2 {
              :Mineral-name       {:value "Silver"}
              :Color              {:value "Silvered"}
              :Weight             {:value 2313.23}
              :Count              {:value 425}
              :Price              {:value 12345.12}
              :DeliveryContainers {:value-1 {:value 4}
                                   :value-2 {:value 5}
                                   :value-3 {:value 6}}
              :Sold               {:value false}
              }
    }
   ]
)

And I am trying to convert it to the following string:我正在尝试将其转换为以下字符串:

"
  [{
    "Minerals": [{
                  "Mineral-1": {
                                "Mineral-name": "Gold",
                                "Color": "Golden",
                                "Weight": 2324.23,
                                "Count": 203,
                                "Price": 20320.49,
                                "DeliveryContainers": [1, 2, 3]
                                },
                  "Mineral-2": {
                                "Mineral-name": "Silver",
                                "Color": "Silver",
                                "Weight": 2342.56,
                                "Count": 234,
                                "Price": 23123.23,
                                "DeliveryContainers": [4, 5, 6]
                                }
                  }]
    }]"

Assuming you restrict yourself to a limited subset of Clojure structures, here is an example that you can use (if you excuse the poor formatting).假设您将自己限制在 Clojure 结构的有限子集中,这里有一个您可以使用的示例(如果您原谅糟糕的格式)。

user> (def hmap
        [ { :Mineral-1 {
                        :Mineral-name       {:value "Gold"}
                        :Color              {:value "Golden"}
                        :Weight             {:value 2324.23}
                        :Count              {:value 203}
                        :Price              {:value 20320.49}
                        :DeliveryContainers {:value-1 {:value 1}
                                             :value-2 {:value 2}
                                             :value-3 {:value 3}}
                        :Sold               {:value true} } }
         { :Mineral-2 {
                       :Mineral-name       {:value "Silver"}
                       :Color              {:value "Silvered"}
                       :Weight             {:value 2313.23}
                       :Count              {:value 425}
                       :Price              {:value 12345.12}
                       :DeliveryContainers {:value-1 {:value 4}
                                            :value-2 {:value 5}
                                            :value-3 {:value 6}}
                       :Sold               {:value false} } } ])
#'user/hmap
user> (declare print-json) ; forward declaration
#'user/print-json
user> (defn print-json-map [x]
        (print "{ ")
        (run! (fn [[k v]]
                (print (str "\"" (name k) "\""))
                (print ": ")
                (print-json v))
              x)
        (println "}"))
#'user/print-json-map
user> (defn print-json-vec [x]
        (print "[ ")
        (run! #(print-json %) x)
        (println "]"))
#'user/print-json-vec
user> (defn print-json-prim [x]
        (cond (string? x) (print (str "\"" x "\""))
              (number? x) (print x)
              (boolean? x) (print x)
              :else (println "CANNOT HAPPEN")))
#'user/print-json-prim
user> (defn print-json [x]
        (cond (map? x) (print-json-map x)
              (vector? x) (print-json-vec x)
              :else (print-json-prim x)))
#'user/print-json
user> (print-json hmap)
[ { "Mineral-1": { "Mineral-name": { "value": "Gold"}
"Color": { "value": "Golden"}
"Weight": { "value": 2324.23}
"Count": { "value": 203}
"Price": { "value": 20320.49}
"DeliveryContainers": { "value-1": { "value": 1}
"value-2": { "value": 2}
"value-3": { "value": 3}
}
"Sold": { "value": true}
}
}
{ "Mineral-2": { "Mineral-name": { "value": "Silver"}
"Color": { "value": "Silvered"}
"Weight": { "value": 2313.23}
"Count": { "value": 425}
"Price": { "value": 12345.12}
"DeliveryContainers": { "value-1": { "value": 4}
"value-2": { "value": 5}
"value-3": { "value": 6}
}
"Sold": { "value": false}
}
}
]
nil
user> 

Since this is for educational purpose I made a solution using more of Clojure's build in language features:由于这是出于教育目的,我使用更多 Clojure 的内置语言功能制作了一个解决方案:

(import '[clojure.lang Sequential Keyword Symbol])
(import '[java.util Map])
(defprotocol MyJSON
  (to-json [this]))

(def ^:dynamic *indent* 0)

(defmacro indent [& body]
  `(binding [*indent* (inc *indent*)] ~@body))

(def indent-size 2)

(defn indent-space []
  (apply str (repeat (* indent-size *indent*) " ")))

(defn comma-sep
  ([values] (comma-sep values ", "))
  ([values delim]
   (apply str (butlast (interleave values (repeat delim))))))

(extend-protocol MyJSON
  Boolean
  (to-json [this] (str this))
  String
  (to-json [this] this)
  Number
  (to-json [this] (str this))
  nil
  (to-json [_] "null")
  Keyword
  (to-json [this] (name this))
  Symbol
  (to-json [this] (name this))
  Sequential
  (to-json [this] (str "[" (comma-sep (map to-json this)) "]"))
  Map
  (to-json [this] (str "\n" (indent-space) "{\n"
                    (indent (comma-sep
                              (map (fn [[k v]] (str (indent-space) (to-json k) ": " (to-json v))) this)
                              ",\n"))
                    "\n"
                    (indent-space) "}" )))

Regarding {:value "1"} , which transforms "1", to and {:value-1 "1":value-2 "2"} , which transforms to ["1" "2"] : I suggest to do this transformation first and finally convert the transformed data to json.关于{:value "1"} ,它将 "1" 转换为和{:value-1 "1":value-2 "2"} ,它转换为["1" "2"] :我建议这样做这个转换首先最后将转换后的数据转换为json。

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

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