3

Using Groovy, requirement is to collect a map's nested element values, along with its top-level element value.

Unsure if a recursive method is needed.

Sample JSON

{
"items": [
      {
      "attribute": "Type",
      "options":       
      [
                  {
            "label": "Type1",
            "value": "1"
         },
                  {
            "label": "Type2",
            "value": "2"
         }

      ]
   },
      {
      "attribute": "Size",
      "options":       [
                  {
            "label": "SizeA",
            "value": "A"
         },
                  {
            "label": "SizeB",
            "value": "B"
         }
      ]
   }
]
}

Expected output after collect

[
{attribute=Type,label=Type1,value=1},
{attribute=Type,label=Type2,value=2},
{attribute=Size,label=SizeA,value=A},
{attribute=Size,label=SizeB,value=B}
]
NScara
  • 55
  • 6

2 Answers2

6

You can solve this combining multiple lists of options obtained through the collect method using a collectMany.

See the following snippet of code:

def input = """
{
  "items": [
    {
      "attribute": "Type",
      "options": [
         {
           "label": "Type1",
           "value": "1"
         },
         {
           "label": "Type2",
           "value": "2"
         }
      ]
   },
   {
     "attribute": "Size",
     "options": [
         {
            "label": "SizeA",
            "value": "A"
         },
         {
            "label": "SizeB",
            "value": "B"
         }
     ]
  } ]
}"""

def json = new groovy.json.JsonSlurper().parseText(input)

/* collectMany directly flatten the two sublists 
 * [ [ [ type1 ], [ type2 ] ], [ [ sizeA ], [ sizeB ] ] ]
 * into
 * [ [type1], [type2], [sizeA], [sizeB] ]
 */
def result = json.items.collectMany { item ->
    // collect returns a list of N (in this example, N=2) elements 
    // [ [ attribute1: ..., label1: ..., value1: ... ],
    //   [ attribute2: ..., label2: ..., value2: ... ] ]
    item.options.collect { option ->
        // return in [ attribute: ..., label: ..., value: ... ]
        [ attribute: item.attribute ] + option
    }
}

assert result == [
    [ attribute: "Type", label: "Type1", value: "1" ],
    [ attribute: "Type", label: "Type2", value: "2" ],
    [ attribute: "Size", label: "SizeA", value: "A" ],
    [ attribute: "Size", label: "SizeB", value: "B" ],
]
Giuseppe Ricupero
  • 6,134
  • 3
  • 23
  • 32
0

Thanks to Giuseppe! I had solved this using a less groovy method:

def result  = [];//Create new list with top-level element and nested elements
json.items.each {item ->
    result.addAll(item.options.collect{ option ->
        [attribute: /"${item?.attribute?:''}"/, label: /"${option?.label?:''}"/, value: /"${option?.value?:''}"/ ]
    })
};
NScara
  • 55
  • 6
  • 1
    Happy to see that you have found something that fits your codebase. Beware that using `/"${item?.attribute?:''}"/` you are altering `attribute` wrapping it with double quotes `"value"`. So in json you will obtain `"attribute":"\"Type\""` instead of the expected `"attribute":"Type"`. To fix it, simply leave just `item?.attribute ?: ''` in place of `/"${item?.attribute?:''}"/`. – Giuseppe Ricupero Jun 07 '19 at 08:44