skip to Main Content

I came across this scenario of implementing grouping on the basis of JavaScript object properties.

Here’s the input:

[
  {
    'A': 1,
    'B': 5,
    'C': 7,
    'D': 67
  },
  {
    'A': 1,
    'B': 5,
    'C': 7,
    'D': 69
  }
]

Here’s the output I am expecting:

{
  name: 1,
  children: [
    {
      name: 5,
      children: [
        {
          name: 7,
          children: [
            {
              name: 67
            },
            {
              name: 69
            }
          ]
        }
      ]
    }
  ]
}

The reason why I am looking for the above output is that I am planning to use it in one of the charts which expects data this way.

Another example input:

[
  {
    'A': 1,
    'B': 5,
    'C': 4,
    'D': 67
  },
  {
    'A': 1,
    'B': 5,
    'C': 7,
    'D': 69
  }
]

Expected output:

{
  name: 1,
  children: [
    {
      name: 5,
      children: [
        {
          name: 4,
          children: [
            {
              name: 67
            }
          ]
        },
        {
          name: 7,
          children: [
            {
              name: 69
            }
          ]
        }
      ]
    }
  ]
}

The first property that is A will always remain the same, rest of the properties can differ and based on which output can also change.

I am trying to pass in the input data and the keys based on which I want to group this data on – which in my case is [A, B, C, D]

  const cstmKey = keys[0];
  const grpdData = {
    name: data[0][cstmKey],
  };

  const grpdValues = data.reduce((acc, item) => {
    const customValue = item[cstmKey];
    if (!acc.includes(customValue)) {
      acc.push(customValue);
    }
    return acc;
  }, []);

I am planning to map on the ‘grpdData’. But not able to come up with anything substantial.

For ordering I was trying to implement it on the basis of a different variable where I can define the order. For eg. – const order = [‘A’, ‘B’, ‘C’, ‘D’]

3

Answers


  1. I would first create a nested object where the keys of your input objects are also keys in the nested object. So for your example, I would first create this:

    {
        "1": {
            "5": {
                "7": {
                    "67": {},
                    "69": {}
                }
            }
        }
    }
    

    Then convert that object to your target structure with a recursive function.

    Like this:

    function convert(data, keys) {
        const hierarchy = node => Object.entries(node).map(([name, child]) =>
                Object.keys(child).length ? { name, children: hierarchy(child) } : { name }
            );
    
        const root = {};
        for (const obj of data) {
            let node = root;
            for (const key of keys) node = (node[obj[key]] ??= {});
        }
        return hierarchy(root)[0];
    }
    
    // Example run
    const data = [{'A': 1,'B': 5,'C': 7,'D': 67},{'A': 1,'B': 5,'C': 7,'D': 69}];
    const result = convert(data, ["A", "B", "C", "D"]);
    console.log(result);
    Login or Signup to reply.
  2. by analyzing the scenario i think you want to destructure array ob object like for each object entry there is another object nested.
    Try this, it might help you.

    function createNestedObject(arr) {
        const result = {};
      
        for (const obj of arr) {
          let currentNode = result;
      
          for (const [key, value] of Object.entries(obj)) {
            if (!currentNode.children) {
              currentNode.children = [];
            }
      
            let nextNode = currentNode.children.find(node => node.name === value);
      
            if (!nextNode) {
              nextNode = { name: value };
              currentNode.children.push(nextNode);
            }
      
            currentNode = nextNode;
          }
        }
      
        return result.children[0];
      }
      
      const inputArray = [
        {
          'A': 1,
          'B': 5,
          'C': 7,
          'D': 67
        },
        {
          'A': 1,
          'B': 5,
          'C': 7,
          'D': 69
        }
      ];
      
      const nestedObject = createNestedObject(inputArray);
      console.log(JSON.stringify(nestedObject, null, 2));
    Login or Signup to reply.
  3. As you have your input and hierarchy declared, you can use the following algorithm to create your tree result item by item. I would note that you final result needs to be an array as well (not an object) and the leaf items have a children field as well, but it will be empty. This falls from the consistency of the tree and its nodes.

    The code below solves the problem and I tried to walk through what each line(s) is doing.

    const input = [
        { 'A': 1, 'B': 5, 'C': 7, 'D': 67 },
        { 'A': 1, 'B': 5, 'C': 7, 'D': 69 }
    ];
    const hierarchy = ['A', 'B', 'C', 'D'];
    
    function getTree(input, hierarchy) {
        // declare tree
        const tree = [];
        // start cursor at tree root
        let cursor = tree;
        // loop through items of the input
        for (const branch of input) {
            // loop through each level of the hierarchy order
            for (const level of hierarchy) {
                // if node found, move on, if not, add it
                let node = cursor.find(({ name }) => (name === branch[level]));
                if (!node) {
                    node = { name: branch[level], children: [] };
                    cursor.push(node);
                }
                // move cursor forward
                cursor = node.children;
            }
            // hierarchy ended, reset cursor to tree root
            cursor = tree;
        }
        return tree;
    }
    
    console.log(getTree(input, hierarchy));
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search