I want to write the function which can take an array of JSON to tree-structure JSON of array.
I have an Array of JSON like this:
var rawData = [{
"dimension": ["a", "c", "f"],
"metric": [26]
}, {
"dimension": ["a", "b", "e"],
"metric": [12]
}, {
"dimension": ["a", "d", "e"],
"metric": [7]
}, {
"dimension": ["a", "b", "f"],
"metric": [5]
}, {
"dimension": ["a", "c", "e"],
"metric": [2]
}, {
"dimension": ["a", "d", "f"],
"metric": [1]
}, {
"dimension": ["a", "k", ""],
"metric": [2]
},{
"dimension": ["b", "c", "d"],
"metric": [2]
}];
I'm expecting output like this:
output:
{
name: 'start',
children: [{
name: 'a',
children: [{
name: 'c',
children: [{
name: 'f',
value: 26
}, {
name: 'e',
value: 2
}]
},
{
name: 'b',
children: [{
name: 'e',
value: 12
}, {
name: 'f',
value: 5
}]
},
{
name: 'd',
children: [{
name: 'e',
value: 7
}, {
name: 'f',
value: 1
}]
},
{
name: 'k',
value: 2
}
]
},
{
name: 'b',
children: [{
name: 'c',
children: [{
name: 'd',
value: 2
}]
}]
}
]
}
Please help me with a small query. I don't think that we need more details regarding this. If you want any other feel free to comment on this post.
Edit: To make the question more simple to understand.
Edit my code
var output = {
name: "start",
children: []
};
var len = rawData.length;
for (var i = 0; i < len; i++) {
rawChild = rawData[i];
cat = createJson({}, rawChild.dimension.filter(n => n), rawChild.metric[0]);
if (i == 0)
output.children.push(cat);
else {
mergeData(output, output.children, cat);
}
}
function mergeData(parent, child, cat) {
if (child) {
for (var index = 0; index < child.length; index++) {
var element = child[index];
if (cat.children) {
if (element.name == cat.name) {
parent = mergeData(element, element.children, cat.children[0]);
return parent;
} else {
continue;
}
} else {
if (element.name == cat.name) {
parent = mergeData(element, element.children, cat);
return parent;
} else {
continue;
}
}
}
parent.children.push(cat);
return parent;
} else {
return;
}
}
console.log(util.inspect(output, false, null, true));
function createJson(mainObj, names, value) {
if (!Array.isArray(names)) {
mainObj.name = names;
mainObj.value = value;
return mainObj;
} else {
for (var index = 0; index < names.length; index++) {
if (index == names.length - 1) {
mainObj = createJson(mainObj, names[index], value);
} else {
mainObj.name = names[index];
newarr = names;
newarr.shift();
mainObj.children = [createJson({}, newarr, value)];
}
}
}
return mainObj;
}
You could take a nested loop approach by iterating rawData
and the dimention
array while saving the last item for the final object and reduce the other given names until the final children array is found.
In the inner lopp, a lookup is made for a children of the same name and if not found, a new data set is generated and inserted.
The use of an external check for childrrem helps for shorter pathes, which have no children properties.
var rawData = [{ dimension: ["a", "c", "f"], metric: [26] }, { dimension: ["a", "b", "e"], metric: [12] }, { dimension: ["a", "d", "e"], metric: [7] }, { dimension: ["a", "b", "f"], metric: [5] }, { dimension: ["a", "c", "e"], metric: [2] }, { dimension: ["a", "d", "f"], metric: [1] }, { dimension: ["a", "k", ""], metric: [2] }, { dimension: ["b", "c", "d"], metric: [2] }],
result = { name: "start", children: [] };
rawData.forEach(({ dimension: path, metric: [value] }) => {
while (!path[path.length - 1]) path.pop(); // remove falsy values from end
var name = path.pop();
path
.reduce((result, name) => {
var temp = result.find(o => o.name === name);
if (!temp) {
result.push(temp = { name });
}
temp.children = temp.children || [];
return temp.children;
}, result.children)
.push({ name, value });
});
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }