Search code examples
arraysjsonjqconcatenation

Group arrays and move them under new object when array names are not known


I have the following JSON

[
    {
        "name": "T1",
        "R10": ["A","B"]
    },
    {
        "name": "T1",
        "M20": ["C"]
    },
    {
        "name": "A1",
        "C20": ["A","B"]
    },
    {
        "name": "B1",
        "V30": ["3"]
    },
    {
        "name": "C1",
        "X50": ["1"]
    }
]

I want to group arrays based on "name" and push them under new "Arrays" object. So the result should look like the following:

[
    {
        "name": "T1",
        "Arrays": {
            "R10": ["A","B"],
            "M20": ["C"]
        }
    },
    {
        "name": "A1",
        "Arrays": {
            "C20": ["A","B"]
        }
    },
    {
        "name": "B1",
        "Arrays": {
            "V30": ["3"]
        }
    },
    {
        "name": "C1",
        "Arrays": {
            "X50": ["1"]
        }
    }
]

I can do a selection based on the value of "name" [.[] | select ( .name | test("T1") )] | add - it does group arrays together, But I can't figure out how to generalize the filter - to apply it to the whole JSON instead of filtering based on the name.

I am also stuck on how to push arrays under the "Arrays" object if I do not know the names of the arrays in advance.


Solution

  • This would definitely need group_by/1 on the .name field and later reorder the objects as desired.

    [ group_by(.name)[] | add ] | map( { name: .name, Arrays: del(.name) } )
    

    Since the group-by functions do an internal sort on the fields applied, i.e. .name in your case, the key ordering of the final result is determined by the ascending order of .name field.

    Demo - jqplay