skip to Main Content

Looking for some help to build a deeply nested data structure in JavaScript.

I will have input data that takes the form like this:

      [
        ["World", "Asia", "Singapore", "Asia-Singapore", "1300"],
        ["World", "Asia", "India", "Asia-India", "850"],
        ["World", "Asia-Singapore", "Bond", "Bond-Singapore", "650"],
        ["World", "Asia-Singapore", "Bond", "Singapore-Bond", "650"],
        ["World", "Asia-China", "Bond", "Bond-China", "600"],
        ["World", "Asia-China", "Bond", "China-Bond", "600"],
        ["World", "Asia-India", "Equity", "Equity-India", "500"],
        ["World", "Asia-India", "Equity", "India-Equity", "500"],
        [
          "World",
          "Asia-China",
          "Private Equity",
          "China-Private Equity",
          "400",
        ],
        [
          "World",
          "Asia-China",
          "Private Equity",
          "Private Equity -China",
          "400",
        ],
        ["World", "Asia-India", "Bond", "Bond-India", "350"],
        ["World", "Asia-India", "Bond", "India-Bond", "350"],
        [
          "Jupiter",
          "Asia-Singapore",
          "Private Equity",
          "Private Equity -Singapore",
          "350",
        ],
        [
          "Jupiter",
          "Asia-Singapore",
          "Private Equity",
          "Singapore-Private Equity",
          "350",
        ],
        ["Jupiter", "Asia-Singapore", "Equity", "Equity-Singapore", "300"],
        ["Jupiter", "Asia-Singapore", "Equity", "Singapore-Equity", "300"],
        ["Jupiter", "Asia", "China", "Asia-China", "Franky", "290"],
        ["World", "Asia-China", "Equity", "China-Equity", "250"],
        ["World", "Asia-China", "Equity", "Equity-China", "250"],
        ["World", "Asia", "China", "Asia-China", "Billy", "110"],
        ["World", "Asia", "China", "Asia-China", "Freddy", "50"],
      ];

With an unpredictable number of columns in each row and I need to be able to create an output with the following structure (does not eactly match values from above, but required structure should be clear):

   const testData = [
      {
        name: "World",
        children: [
          {
            name: "Asia",
            children: [
              {
                name: "Asia-China",
                value: 110,
              },
            ],
          },
        ],
      },
      {
        name: "Jupiter",
        children: [
          {
            name: "Asia-Singapore",
            children: [
              {
                name: "Google",
                value: 200,
              },
            ],
          },
        ],
      },
    ];

So it will need to loop through each row though the flat array given (always with the ‘Value’ as the last item in the array that is the row, but not necessarily the same number of other values every time) and create groups for as many levels as there are, nesting child nodes and then putting the ‘Value’ value when there are no child nodes to add.

Hopefully someone can help me structure this up – I get all tied up in mental knots when it comes to anything recursive like this.

2

Answers


  1. You could use Array.reduceRight and populate the output data like so. It iterates from the inner most level and deal with the last two elements exceptionally, then populate the outer structures layer by layer.

    const input = [
      ["World", "Asia", "Singapore", "Asia-Singapore", "1300"],
      ["World", "Asia", "India", "Asia-India", "850"],
      ["Jupiter", "Asia-Singapore", "Private Equity", "Private Equity -Singapore", "350"]
    ];
    
    const output = input.map(arr => arr.reduceRight((acc, name, i, arr) => {
      if (i >= arr.length - 2) {
        return { name, value: +acc };
      }
    
      return { name, children: [acc] };
    }));
    
    console.log(output);
    Login or Signup to reply.
  2. My suggestions are:

    • First, iterate over each row.

    • For each level, find or create a node.

    • Move deeper in structure until the last value is reached

    • Add value to final node.

    const data = [
      ["World", "Asia", "Singapore", "Asia-Singapore", "1300"],
      ["World", "Asia", "India", "Asia-India", "850"],
      // more rows...
    ];
    
    function buildTree(data) {
      const result = [];
    
      data.forEach((row) => {
        let currentLevel = result;
        row.slice(0, -1).forEach((name) => {
          let existing = currentLevel.find(item => item.name === name);
          if (!existing) {
            existing = { name, children: [] };
            currentLevel.push(existing);
          }
          currentLevel = existing.children;
        });
    
        currentLevel.push({ name: row[row.length - 2], value: parseInt(row[row.length - 1]) });
      });
    
      return result;
    }
    
    const nestedData = buildTree(data);
    console.log(JSON.stringify(nestedData, null, 2));
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search