如何在 Groovy 中展平和拆分此 JSON?
How to flatten and split this JSON in Groovy?
我可以借助一些帮助编写 Groovy 脚本,根据嵌套数组元素将 JSON 展平并拆分为多个 JSON-s。这里是原文JSON:
{
"input_query": {
"discount_guid": "3afeb169-7969-4f6f-8928-d801692848b1",
"user_uid": 5467890,
"shopping_list": [
{
"article_id": 311729,
"current_price_without_promo": 7.69,
"promo_discount": 0,
"count": 1,
"apply_discount": true
},
{
"article_id": 229752,
"current_price_without_promo": 11.29,
"promo_discount": 0,
"count": 1,
"apply_discount": true
},
{
"article_id": 193672,
"current_price_without_promo": 79.99,
"promo_discount": 0,
"count": 1,
"apply_discount": true
},
{
"article_id": 261657,
"current_price_without_promo": 16.99,
"promo_discount": 0,
"count": 1,
"apply_discount": true
},
{
"article_id": 318153,
"current_price_without_promo": 13.99,
"promo_discount": 0,
"count": 1,
"apply_discount": true
}
],
"discount_params_per_article": [
{
"article_id": 311729,
"min_discount": 0,
"max_discount": 4.12,
"imposed_discount": null,
"article_target_probability_increase": 1.15,
"discount_downscale_factor": 1
},
{
"article_id": 229752,
"min_discount": 0,
"max_discount": 7.52,
"imposed_discount": null,
"article_target_probability_increase": 1.15,
"discount_downscale_factor": 1
},
{
"article_id": 193672,
"min_discount": 0,
"max_discount": 60,
"imposed_discount": null,
"article_target_probability_increase": 1.15,
"discount_downscale_factor": 1
},
{
"article_id": 261657,
"min_discount": 0,
"max_discount": 12.4,
"imposed_discount": null,
"article_target_probability_increase": 1.15,
"discount_downscale_factor": 1
},
{
"article_id": 318153,
"min_discount": 0,
"max_discount": 8,
"imposed_discount": null,
"article_target_probability_increase": 1.15,
"discount_downscale_factor": 1
}
],
"target_probability_increase": null,
"request_time": "2019-12-21T21:32:13.018635"
},
"total_discount": 0.94,
"article_discounts": [
{
"article_id": 311729,
"discount": 0.04
},
{
"article_id": 229752,
"discount": 0.08
},
{
"article_id": 193672,
"discount": 0.61
},
{
"article_id": 261657,
"discount": 0.13
},
{
"article_id": 318153,
"discount": 0.08
}
]
}
我想做的是将原来的 JSON 扁平化为一个 JSON-s 数组,如下所示:
[{
"discount_guid": "3afeb169-7969-4f6f-8928-d801692848b1",
"user_uid": 5467890,
"article_id": 318153,
"current_price_without_promo": 13.99,
"promo_discount": 0,
"count": 1,
"apply_discount": true,
"min_discount": 0,
"max_discount": 8,
"imposed_discount": null,
"article_target_probability_increase": 1.15,
"discount_downscale_factor": 1,
"target_probability_increase": null,
"request_time": "2019-12-21T21:32:13.018635",
"total_discount": 0.94,
"discount": 0.08
},
{
"discount_guid": ...
},
...
]
我已经设法通过这种方式弄平了 JSON:
import groovy.json.JsonOutput as jo
def content = new File('response.json')
def slurper = new groovy.json.JsonSlurper()
def object = slurper.parseText(content)
def flattenMap(Map map) {
def result = [:]
map.each { k, v ->
if (v instanceof Map) {
result << flattenMap(v)
} else if (v instanceof Collection && v.every {it instanceof Map}) {
v.each {
result << flattenMap(it)
}
} else {
result[k] = v
}
}
result
}
println(jo.prettyPrint(jo.toJson(flattenMap(object))))
但我不知道如何获得完整的 JSON-s 数组。我确信有一种简单的方法可以完成此操作,但我对 Groovy 还很陌生,到目前为止我还没有找到解决方案。任何帮助将不胜感激。
解决这个问题的一种方法是这样的:
import groovy.json.*
def str = '''
{
"input_query": {
"discount_guid": "3afeb169-7969-4f6f-8928-d801692848b1",
"user_uid": 5467890,
"shopping_list": [
{
"article_id": 311729,
"current_price_without_promo": 7.69,
"promo_discount": 0,
"count": 1,
"apply_discount": true
},
{
"article_id": 229752,
"current_price_without_promo": 11.29,
"promo_discount": 0,
"count": 1,
"apply_discount": true
},
{
"article_id": 193672,
"current_price_without_promo": 79.99,
"promo_discount": 0,
"count": 1,
"apply_discount": true
},
{
"article_id": 261657,
"current_price_without_promo": 16.99,
"promo_discount": 0,
"count": 1,
"apply_discount": true
},
{
"article_id": 318153,
"current_price_without_promo": 13.99,
"promo_discount": 0,
"count": 1,
"apply_discount": true
}
],
"discount_params_per_article": [
{
"article_id": 311729,
"min_discount": 0,
"max_discount": 4.12,
"imposed_discount": null,
"article_target_probability_increase": 1.15,
"discount_downscale_factor": 1
},
{
"article_id": 229752,
"min_discount": 0,
"max_discount": 7.52,
"imposed_discount": null,
"article_target_probability_increase": 1.15,
"discount_downscale_factor": 1
},
{
"article_id": 193672,
"min_discount": 0,
"max_discount": 60,
"imposed_discount": null,
"article_target_probability_increase": 1.15,
"discount_downscale_factor": 1
},
{
"article_id": 261657,
"min_discount": 0,
"max_discount": 12.4,
"imposed_discount": null,
"article_target_probability_increase": 1.15,
"discount_downscale_factor": 1
},
{
"article_id": 318153,
"min_discount": 0,
"max_discount": 8,
"imposed_discount": null,
"article_target_probability_increase": 1.15,
"discount_downscale_factor": 1
}
],
"target_probability_increase": null,
"request_time": "2019-12-21T21:32:13.018635"
},
"total_discount": 0.94,
"article_discounts": [
{
"article_id": 311729,
"discount": 0.04
},
{
"article_id": 229752,
"discount": 0.08
},
{
"article_id": 193672,
"discount": 0.61
},
{
"article_id": 261657,
"discount": 0.13
},
{
"article_id": 318153,
"discount": 0.08
}
]
}
'''
def json = new JsonSlurper().parseText(str)
// a predicate to check if a value is a plain value vs map or list
def isPlain = { v -> !(v instanceof Map) && !(v instanceof List) }
// for the two maps json.input_query and the root level json map,
// find all plain values
def plainValues = json.input_query.findAll { k, v -> isPlain(v) } +
json.findAll { k, v -> isPlain(v) }
// find the three lists of maps, group by article_id and add the
// values for each article id to a cumulative map and finally
// add the plain values collected above to each cumulative map
def result = (json.input_query.shopping_list +
json.input_query.discount_params_per_article +
json.article_discounts).groupBy {
it.article_id
}.values().collect { listOfMaps ->
listOfMaps.sum() + plainValues
}
// print result
result.each { m ->
println "-----"
m.sort().each { k, v ->
println "${k.padLeft(35)} -> $v"
}
}
执行上面的命令会产生:
─➤ groovy solution.groovy
-----
apply_discount -> true
article_id -> 311729
article_target_probability_increase -> 1.15
count -> 1
current_price_without_promo -> 7.69
discount -> 0.04
discount_downscale_factor -> 1
discount_guid -> 3afeb169-7969-4f6f-8928-d801692848b1
imposed_discount -> null
max_discount -> 4.12
min_discount -> 0
promo_discount -> 0
request_time -> 2019-12-21T21:32:13.018635
target_probability_increase -> null
total_discount -> 0.94
user_uid -> 5467890
-----
apply_discount -> true
article_id -> 229752
article_target_probability_increase -> 1.15
count -> 1
current_price_without_promo -> 11.29
discount -> 0.08
discount_downscale_factor -> 1
discount_guid -> 3afeb169-7969-4f6f-8928-d801692848b1
imposed_discount -> null
max_discount -> 7.52
min_discount -> 0
promo_discount -> 0
request_time -> 2019-12-21T21:32:13.018635
target_probability_increase -> null
total_discount -> 0.94
user_uid -> 5467890
-----
...
末尾的打印输出按键排序,并为了可读性做了一些缩进。
然后您可以使用如下方式获得输出 json:
def outputJson = JsonOutput.toJson(result)
我可以借助一些帮助编写 Groovy 脚本,根据嵌套数组元素将 JSON 展平并拆分为多个 JSON-s。这里是原文JSON:
{
"input_query": {
"discount_guid": "3afeb169-7969-4f6f-8928-d801692848b1",
"user_uid": 5467890,
"shopping_list": [
{
"article_id": 311729,
"current_price_without_promo": 7.69,
"promo_discount": 0,
"count": 1,
"apply_discount": true
},
{
"article_id": 229752,
"current_price_without_promo": 11.29,
"promo_discount": 0,
"count": 1,
"apply_discount": true
},
{
"article_id": 193672,
"current_price_without_promo": 79.99,
"promo_discount": 0,
"count": 1,
"apply_discount": true
},
{
"article_id": 261657,
"current_price_without_promo": 16.99,
"promo_discount": 0,
"count": 1,
"apply_discount": true
},
{
"article_id": 318153,
"current_price_without_promo": 13.99,
"promo_discount": 0,
"count": 1,
"apply_discount": true
}
],
"discount_params_per_article": [
{
"article_id": 311729,
"min_discount": 0,
"max_discount": 4.12,
"imposed_discount": null,
"article_target_probability_increase": 1.15,
"discount_downscale_factor": 1
},
{
"article_id": 229752,
"min_discount": 0,
"max_discount": 7.52,
"imposed_discount": null,
"article_target_probability_increase": 1.15,
"discount_downscale_factor": 1
},
{
"article_id": 193672,
"min_discount": 0,
"max_discount": 60,
"imposed_discount": null,
"article_target_probability_increase": 1.15,
"discount_downscale_factor": 1
},
{
"article_id": 261657,
"min_discount": 0,
"max_discount": 12.4,
"imposed_discount": null,
"article_target_probability_increase": 1.15,
"discount_downscale_factor": 1
},
{
"article_id": 318153,
"min_discount": 0,
"max_discount": 8,
"imposed_discount": null,
"article_target_probability_increase": 1.15,
"discount_downscale_factor": 1
}
],
"target_probability_increase": null,
"request_time": "2019-12-21T21:32:13.018635"
},
"total_discount": 0.94,
"article_discounts": [
{
"article_id": 311729,
"discount": 0.04
},
{
"article_id": 229752,
"discount": 0.08
},
{
"article_id": 193672,
"discount": 0.61
},
{
"article_id": 261657,
"discount": 0.13
},
{
"article_id": 318153,
"discount": 0.08
}
]
}
我想做的是将原来的 JSON 扁平化为一个 JSON-s 数组,如下所示:
[{
"discount_guid": "3afeb169-7969-4f6f-8928-d801692848b1",
"user_uid": 5467890,
"article_id": 318153,
"current_price_without_promo": 13.99,
"promo_discount": 0,
"count": 1,
"apply_discount": true,
"min_discount": 0,
"max_discount": 8,
"imposed_discount": null,
"article_target_probability_increase": 1.15,
"discount_downscale_factor": 1,
"target_probability_increase": null,
"request_time": "2019-12-21T21:32:13.018635",
"total_discount": 0.94,
"discount": 0.08
},
{
"discount_guid": ...
},
...
]
我已经设法通过这种方式弄平了 JSON:
import groovy.json.JsonOutput as jo
def content = new File('response.json')
def slurper = new groovy.json.JsonSlurper()
def object = slurper.parseText(content)
def flattenMap(Map map) {
def result = [:]
map.each { k, v ->
if (v instanceof Map) {
result << flattenMap(v)
} else if (v instanceof Collection && v.every {it instanceof Map}) {
v.each {
result << flattenMap(it)
}
} else {
result[k] = v
}
}
result
}
println(jo.prettyPrint(jo.toJson(flattenMap(object))))
但我不知道如何获得完整的 JSON-s 数组。我确信有一种简单的方法可以完成此操作,但我对 Groovy 还很陌生,到目前为止我还没有找到解决方案。任何帮助将不胜感激。
解决这个问题的一种方法是这样的:
import groovy.json.*
def str = '''
{
"input_query": {
"discount_guid": "3afeb169-7969-4f6f-8928-d801692848b1",
"user_uid": 5467890,
"shopping_list": [
{
"article_id": 311729,
"current_price_without_promo": 7.69,
"promo_discount": 0,
"count": 1,
"apply_discount": true
},
{
"article_id": 229752,
"current_price_without_promo": 11.29,
"promo_discount": 0,
"count": 1,
"apply_discount": true
},
{
"article_id": 193672,
"current_price_without_promo": 79.99,
"promo_discount": 0,
"count": 1,
"apply_discount": true
},
{
"article_id": 261657,
"current_price_without_promo": 16.99,
"promo_discount": 0,
"count": 1,
"apply_discount": true
},
{
"article_id": 318153,
"current_price_without_promo": 13.99,
"promo_discount": 0,
"count": 1,
"apply_discount": true
}
],
"discount_params_per_article": [
{
"article_id": 311729,
"min_discount": 0,
"max_discount": 4.12,
"imposed_discount": null,
"article_target_probability_increase": 1.15,
"discount_downscale_factor": 1
},
{
"article_id": 229752,
"min_discount": 0,
"max_discount": 7.52,
"imposed_discount": null,
"article_target_probability_increase": 1.15,
"discount_downscale_factor": 1
},
{
"article_id": 193672,
"min_discount": 0,
"max_discount": 60,
"imposed_discount": null,
"article_target_probability_increase": 1.15,
"discount_downscale_factor": 1
},
{
"article_id": 261657,
"min_discount": 0,
"max_discount": 12.4,
"imposed_discount": null,
"article_target_probability_increase": 1.15,
"discount_downscale_factor": 1
},
{
"article_id": 318153,
"min_discount": 0,
"max_discount": 8,
"imposed_discount": null,
"article_target_probability_increase": 1.15,
"discount_downscale_factor": 1
}
],
"target_probability_increase": null,
"request_time": "2019-12-21T21:32:13.018635"
},
"total_discount": 0.94,
"article_discounts": [
{
"article_id": 311729,
"discount": 0.04
},
{
"article_id": 229752,
"discount": 0.08
},
{
"article_id": 193672,
"discount": 0.61
},
{
"article_id": 261657,
"discount": 0.13
},
{
"article_id": 318153,
"discount": 0.08
}
]
}
'''
def json = new JsonSlurper().parseText(str)
// a predicate to check if a value is a plain value vs map or list
def isPlain = { v -> !(v instanceof Map) && !(v instanceof List) }
// for the two maps json.input_query and the root level json map,
// find all plain values
def plainValues = json.input_query.findAll { k, v -> isPlain(v) } +
json.findAll { k, v -> isPlain(v) }
// find the three lists of maps, group by article_id and add the
// values for each article id to a cumulative map and finally
// add the plain values collected above to each cumulative map
def result = (json.input_query.shopping_list +
json.input_query.discount_params_per_article +
json.article_discounts).groupBy {
it.article_id
}.values().collect { listOfMaps ->
listOfMaps.sum() + plainValues
}
// print result
result.each { m ->
println "-----"
m.sort().each { k, v ->
println "${k.padLeft(35)} -> $v"
}
}
执行上面的命令会产生:
─➤ groovy solution.groovy
-----
apply_discount -> true
article_id -> 311729
article_target_probability_increase -> 1.15
count -> 1
current_price_without_promo -> 7.69
discount -> 0.04
discount_downscale_factor -> 1
discount_guid -> 3afeb169-7969-4f6f-8928-d801692848b1
imposed_discount -> null
max_discount -> 4.12
min_discount -> 0
promo_discount -> 0
request_time -> 2019-12-21T21:32:13.018635
target_probability_increase -> null
total_discount -> 0.94
user_uid -> 5467890
-----
apply_discount -> true
article_id -> 229752
article_target_probability_increase -> 1.15
count -> 1
current_price_without_promo -> 11.29
discount -> 0.08
discount_downscale_factor -> 1
discount_guid -> 3afeb169-7969-4f6f-8928-d801692848b1
imposed_discount -> null
max_discount -> 7.52
min_discount -> 0
promo_discount -> 0
request_time -> 2019-12-21T21:32:13.018635
target_probability_increase -> null
total_discount -> 0.94
user_uid -> 5467890
-----
...
末尾的打印输出按键排序,并为了可读性做了一些缩进。
然后您可以使用如下方式获得输出 json:
def outputJson = JsonOutput.toJson(result)