如何在Groovy中扁平化和拆分此JSON?

问题描述 投票:0回答:1

我可以在编写Groovy脚本时使用一些帮助,以基于嵌套数组元素将JSON展平并拆分为多个JSON。这是原始的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来说我还是很陌生,到目前为止,我还没有找到解决方案。任何帮助将不胜感激。

json groovy nested flatten
1个回答
0
投票

解决这个问题的一种方法是这样的:

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
-----
...

末尾的打印输出按键排序,并进行一些缩进以提高可读性。

© www.soinside.com 2019 - 2024. All rights reserved.