我有2个完全相似的JSON对象,我想添加相应键的值并返回单个JSON。 JSON也将包含JSON数组。在clojure中做什么是惯用的方式?
输入JSON 1:
{
"data":[
{
"val1":{
"total":"1.00",
"val2":{
"total":"1.00"
},
"val3":{
"total":"1.00"
}
}
}
]
}
输入JSON 2:
{
"data":[
{
"val1":{
"total":"2.00",
"val2":{
"total":"3.00"
},
"val3":{
"total":"4.00"
}
}
}
]
}
预期的JSON:
{
"data":[
{
"val1":{
"total":"3.00",
"val2":{
"total":"4.00"
},
"val3":{
"total":"5.00"
}
}
}
]
}
答案 0 :(得分:3)
首先你需要解析json。
将[org.clojure/data.json "0.2.6"]
添加到您的:dependencies
向量。
(ns foo.bar
(:require
[clojure.data.json :as json]))
(defn read-input [path]
;; Substitute slurp for however you get the input.
(json/read-str (slurp path)
:key-fn keyword ; In clojure it's nice to have keys as keywords
:value-fn (fn [k v]
;; Parse the numbers.
(if (= :total k)
(Double/parseDouble v)
v))))
(def input1 (read-input "input1.json"))
(def input2 (read-input "input2.json"))
;; The parsed input.
(def input1 {:data [{:val1 {:total 5.0, :val2 {:total 4.0}, :val3 {:total 3.0}}}]})
(def input2 {:data [{:val1 {:total 1.0, :val2 {:total 1.0}, :val3 {:total 1.0}}}]})
然后要合并它们,你可以使用漂亮的核心函数merge-with
和一些递归。
(defn merge-jsons [a b]
(merge-with (fn [v1 v2]
(cond (every? vector? [v1 v2]) (mapv merge-jsons v1 v2)
(every? map? [v1 v2]) (merge-jsons v1 v2)
:else (+ v1 v2)))
a, b))
然后你只需要将它转换回json。
(write-str
有一个:value-fn
选项,就像read-str
一样,如果你真的需要这里的数字是字符串的话)
(json/write-str (merge-jsons input1 input2))
;;=> "{\"data\":[{\"val1\":{\"total\":3.0,\"val2\":{\"total\":4.0},\"val3\":{\"total\":5.0}}}]}"
答案 1 :(得分:0)
这可以通过3个步骤来实现。我在下面的代码中提到了它们作为注释。
(def input1 {:val1 {:total 5, :val2 {:total 4}, :val3 {:total 3}}})
(def input2 {:val1 {:total 1, :val2 {:total 1}, :val3 {:total 1}}})
;; Step 1: Flatten the data
(defn flatten-input [input]
(let [values (str "[" (clojure.string/replace (str input) #"([{]*[:]*[a-zA-Z]+[1-9]*)|([}])|([,])" "") "]")]
(read-string values)))
;; Step 2: Sum the data
(defn sum-the-data [& inputs]
(apply map + inputs))
;; Step 3: Convert it into the original data structure
(defn get-final-data [summed-data]
(let [string-data (apply format "{:val1 {:total %s, :val2 {:total %s}, :val3 {:total %s}}}" summed-data)]
(read-string string-data)))
(defn main []
(let [flattened-input1 (flatten-input input1)
flattened-input2 (flatten-input input2)
summed-data (sum-the-data flattened-input1 flattened-input2)]
(prn (get-final-data summed-data))))
免责声明:这只适用于没有矢量的数据结构。
注意:请评论可能比传统方法更耗时的任何事情。