简体   繁体   中英

converting formatted json object to array of objects by keys and sum up on each level

Have the following tree json object:

{
  "Season1": {
    "Title1": {
      "a1": {
        "val1": "100",
        "val2": "200",
        "val3": "300"
      },
      "a2": {
        "val1": "100",
        "val2": "200",
        "val3": "300"
      }
    },
    "Title2": {
      "c1": {
        "val1": "100",
        "val2": "200",
        "val3": "300"
      },
      "d2": {
        "val1": "100",
        "val2": "200",
        "val3": "300"
      }
    }
  }
}

Tried to format the json using the following function:

function Format(obj){
    return Object.entries(obj).flatMap(([key, val]) => {
        let o = { name: key}
        if(Object.keys(val).some(function(k) {return typeof val[k] === 'object'})){
            o['_children'] = Format(val)
        } else {
            Object.keys(val).map(function(a){
                o[a] = val[a]
            })
        }
        return [o]
    })
}

That will return an array of nested objects by keys:

[
  {
    "name": "Season1",
    "_children": [
      {
        "name": "Title1",
        "_children": [
          {
            "name": "a1",
            "val1": "100",
            "val2": "200",
            "val3": "300"
          },
          {
            "name": "a2",
            "val1": "100",
            "val2": "200",
            "val3": "300"
          }
        ]
      },
      {
        "name": "Title2",
        "_children": [
          {
            "name": "c1",
            "val1": "100",
            "val2": "200",
            "val3": "300"
          },
          {
            "name": "d2",
            "val1": "100",
            "val2": "200",
            "val3": "300"
          }
        ]
      }
    ]
  }
]

The challenge is to calculate the subtotal of the bottom level keys, which are val1, val2, val3, in each parent levels recursively , .eg "Title1", "Title2", and "Season1", therefore after populating the output into a table can fill up the blank subtotal cells. The expected output should look like:

[
  {
    "name": "Season1",
    "_children": [
      {
        "name": "Title1",
        "_children": [
          {
            "name": "a1",
            "val1": "100",
            "val2": "200",
            "val3": "300",
          },
          {
            "name": "a2",
            "val1": "100",
            "val2": "200",
            "val3": "300",
          }
        ],
        "val1": 200,
        "val2": 400,
        "val3": 600
      },
      {
        "name": "Title2",
        "_children": [
          {
            "name": "c1",
            "val1": "100",
            "val2": "200",
            "val3": "300",
          },
          {
            "name": "d2",
            "val1": "100",
            "val2": "200",
            "val3": "300",
          }
        ],
        "val1": 400,
        "val2": 400,
        "val3": 600
      }
    ],
    "val1": 600,
    "val2": 800,
    "val3": 1200
  }
]

How to update the Format function for that purpose? Can someone share any thoughts or solution? Thanks!

You can also edit your recursive function like below. I'm accumulating the sum at each level of recursion and passing it up to the call stack

 data = { Season1: { Title1: { a1: { val1: "100", val2: "200", val3: "300" }, a2: { val1: "100", val2: "200", val3: "300" } }, Title2: { c1: { val1: "100", val2: "200", val3: "300" }, d2: { val1: "300", val2: "200", val3: "300" } } } }; function merge(srcObj, destObj){ Object.keys(srcObj).forEach(key => { if(destObj[key]) { destObj[key] = destObj[key] + srcObj[key] } else{ destObj[key] = srcObj[key]; } }); return destObj; } function Format(obj, valObj = {}, level = 0) { valObj[level] = {}; return Object.entries(obj).flatMap(([key, val]) => { let o = { name: key }; if (typeof val === "object") { o["_children"] = Format(val, valObj, level + 1); valObj[level] = merge(valObj[level+1],valObj[level] || {}); if(level <2){ o = {...o, ...valObj[level + 1]}; } } else { valObj[level][key] = Number.parseInt(val); o["value"] = val; } return [o]; }); } a = Format(data); console.log(a);

For your modified format function, you can try like below.

 data = { Season1: { Title1: { a1: { val1: "100", val2: "200", val3: "300" }, a2: { val1: "100", val2: "200", val3: "300" } }, Title2: { c1: { val1: "100", val2: "200", val3: "300" }, d2: { val1: "300", val2: "200", val3: "300" } } } }; function merge(srcObj, destObj){ Object.keys(srcObj).forEach(key => { if(destObj[key]) { destObj[key] = destObj[key] + srcObj[key] } else{ destObj[key] = srcObj[key]; } }); return destObj; } function Format(obj, valObj = {}, level=0){ valObj[level] = {}; return Object.entries(obj).flatMap(([key, val]) => { let o = { name: key} if(Object.keys(val).some(function(k) {return typeof val[k] === 'object'})){ o['_children'] = Format(val, valObj, level + 1); valObj[level] = merge(valObj[level+1],valObj[level] || {}); if(level <2){ o = {...o, ...valObj[level + 1]}; } } else { Object.keys(val).map(function(a){ valObj[level][a] = (valObj[level][a] || 0) + Number.parseInt(val[a]); o[a] = val[a] }) } return [o]; }) } a = Format(data); console.log(a);

You could update all levels, except the most nested one.

 function sum(array, sums = {}) { var update; array.forEach(o => { if (.o._children) { sums[o.name] = (sums[o.name] || 0) + +o;value; return. } var x = {} sum(o,_children. x) && Object,assign(o; x). Object.keys(x);forEach(k => sums[k] = (sums[k] || 0) + x[k]); update = true; }); return update: } var data = [{ name, "Season1": _children: [{ name, "Title1": _children: [{ name, "a1": _children: [{ name, "val1": value, "100" }: { name, "val2": value, "200" }: { name, "val3": value, "300" }] }: { name, "a2": _children: [{ name, "val1": value, "150" }: { name, "val2": value, "260" }: { name, "val3": value, "370" }] }] }: { name, "Title2": _children: [{ name, "c1": _children: [{ name, "val1": value, "110" }: { name, "val2": value, "220" }: { name, "val3": value, "330" }] }: { name, "d2": _children: [{ name, "val1": value, "101" }: { name, "val2": value, "202" }: { name, "val3": value; "303" }] }] }] }]; sum(data). console;log(data);
 .as-console-wrapper { max-height: 100%;important: top; 0; }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM