How to create Flat Array from tree data structure using node indexes?

Viewed 53

I need to create a flat array using various hierarchical tree data. I'll get array of tree nodes as string in the form of parentNode-childNode-... This is all dynamic. I tried to convert treeNodeInput into nested object, but couldn't make use of that.

const TREE_DATA = [{
    name: 'USA',
    children: [{
        name: 'Texas',
        children: [{
            name: 'Dallas'
        }, {
            name: 'Houston'
        }]
    }, {
        name: 'California',
        children: [{
            name: 'Los Angeles'
        }, {
            name: 'San Francisco'
        }]
    }, {
        name: 'New York',
        children: [{
            name: 'New York City'
        }, {
            name: 'Buffalo'
        }]
    }],
}, {
    name: 'India',
    children: [{
        name: 'Bihar',
        children: [{
            name: 'Patna'
        }, {
            name: 'Gaya'
        }],
    }],
}, ];

let treeDataGroupedBy = ['Country', 'State', 'City'];
let treeNodeInput = ['0-0-0', '1-0-1'];
let data = []; /*Expected Result [{
    Country: 'USA',
    State: 'Texas',
    City: 'Dallas'
}, {
    Country: 'India',
    State: 'Bihar',
    City: 'Gaya'
}]*/

for (let item of treeNodeInput) {
    let nodesArray = item.split("-");
    let count = 0;
    let rowObj = {};
    for (let node of nodesArray) {
        rowObj[treeDataGroupedBy[count]] = Object.keys(TREE_DATA)[Number(node)];
                count++;
    }
    data.push(rowObj);
}

console.log(data)

3 Answers

You can get expected result by doing this minimum code change.

const TREE_DATA = [{
    name: 'USA',
    children: [{
        name: 'Texas',
        children: [{
            name: 'Dallas'
        }, {
            name: 'Houston'
        }]
    }, {
        name: 'California',
        children: [{
            name: 'Los Angeles'
        }, {
            name: 'San Francisco'
        }]
    }, {
        name: 'New York',
        children: [{
            name: 'New York City'
        }, {
            name: 'Buffalo'
        }]
    }],
}, {
    name: 'India',
    children: [{
        name: 'Bihar',
        children: [{
            name: 'Patna'
        }, {
            name: 'Gaya'
        }],
    }],
}, ];

let treeDataGroupedBy = ['Country', 'State', 'City'];
let treeNodeInput = ['0-0-0', '1-0-1'];
let data = []; /*Expected Result [{
    Country: 'USA',
    State: 'Texas',
    City: 'Dallas'
}, {
    Country: 'India',
    State: 'Bihar',
    City: 'Gaya'
}]*/

for (let item of treeNodeInput) {
    let nodesArray = item.split("-");
    let count = 0;
    let rowObj = {};
    let child = TREE_DATA
    for (let node of nodesArray) {
            if(child.hasOwnProperty('children')){
                child =child["children"][node]
            }
            else{
                child =child[node]
            }
                rowObj[treeDataGroupedBy[count]] = child.name;
                count++;
      
    }
    data.push(rowObj);
}

console.log(data)

You can do this reccursively:


const TREE_DATA = [{
    name: 'USA',
    children: [{
        name: 'Texas',
        children: [{
            name: 'Dallas'
        }, {
            name: 'Houston'
        }]
    }, {
        name: 'California',
        children: [{
            name: 'Los Angeles'
        }, {
            name: 'San Francisco'
        }]
    }, {
        name: 'New York',
        children: [{
            name: 'New York City'
        }, {
            name: 'Buffalo'
        }]
    }],
}, {
    name: 'India',
    children: [{
        name: 'Bihar',
        children: [{
            name: 'Patna'
        }, {
            name: 'Gaya'
        }],
    }],
}, ];

let treeDataGroupedBy = ['Country', 'State', 'City'];
let treeNodeInput = ['0-0-0', '1-0-1'];
let data = []; 

function LinearifyTree(tree, keys, path) {
  let val = {keys[0]: tree[path[0]].name};
  if (key.length === 1) {
    return val;
  }
  return {...val, ...LinearifyTree(tree[path[0]].children, keys.slice(1), path.slice(1))};
}

for (let item of treeNodeInput) {
  let nodeArray = item.split('-').map(v => Number(v));
  data = LinearifyTree(TREE_DATA, treeDataGroupedBy, nodeArray);
}

console.log(data);

Is it optimal? No Will it work? yes Do you want it to be optimal? Change your data structure

Here is a recursive function to build that desired result.

const TREE_DATA=[{name:'USA',children:[{name:'Texas',children:[{name:'Dallas'},{name:'Houston'}]},{name:'California',children:[{name:'LosAngeles'},{name:'SanFrancisco'}]},{name:'NewYork',children:[{name:'NewYorkCity'},{name:'Buffalo'}]}],},{name:'India',children:[{name:'Bihar',children:[{name:'Patna'},{name:'Gaya'}],}],},];
let treeDataGroupedBy = ['Country', 'State', 'City'];
let result = [];

for (const data of TREE_DATA) {
  buildResult(data, treeDataGroupedBy, 0, {}, result);
}

console.log(result);

function buildResult(data, treeDataGroupedBy, level, obj, result) {
  if (!data || level >= treeDataGroupedBy.length) {
    return;
  }

  const name = treeDataGroupedBy[level]; // 'Country', 'State', or 'City'
  obj[name] = data.name;

  if (!data.children) {
    // No children exists, so no more levels down, so push the object to the result and return.
    result.push(obj);
    return;
  }

  for (let child of data.children) {
    // Children exists, so visit each child. Increment level and pass object copy.
    buildResult(child, treeDataGroupedBy, level + 1, {...obj}, result);
  }
}

Related