How to Pivot Array of Objects with GroupBy and Sum in Javascipt - javascript

I have arr array of objects, I need to pivot it with product,calorie and apply (grouping & sum) on remaining parameters.
And then require data in single object.
I tried below code, it works fine but I divided code in 3 parts.
Could I have better code than this or it is ok.
var arr = [{
"product": "Jam",
"calorie": 2000,
"A": 300,
"B": 500,
"type": "Daily"
},
{
"product": "Sugar",
"calorie": 1000,
"A": 100,
"B": 200,
"type": "Daily"
}
]
var a1 = {}
var a2 = {}
//Step-1 Pivot
for (let i = 0; i < arr.length; i++) {
a1[arr[i]['product']] = arr[i]['calorie'];
}
//Step-2 Group and sum
a2 = groupAndSum(arr, ['type'], ['A', 'B'])[0];
//Step-3 merging.
console.log({ ...a1,
...a2
})
//General grouping and summing function that accepts an
//#Array:Array of objects
//#groupKeys: An array of keys to group by,
//#sumKeys - An array of keys to sum.
function groupAndSum(arr, groupKeys, sumKeys) {
return Object.values(
arr.reduce((acc, curr) => {
const group = groupKeys.map(k => curr[k]).join('-');
acc[group] = acc[group] || Object.fromEntries(groupKeys.map(k => [k, curr[k]]).concat(sumKeys.map(k => [k, 0])));
sumKeys.forEach(k => acc[group][k] += curr[k]);
return acc;
}, {})
);
}

Here a single function which takes 3 params:
const func = (arr, pivot_vals, sum_vals) => {
return arr.reduce((a, v) => {
pivot_vals.forEach((pivot) => {
a[v[pivot[0]]] = v[pivot[1]];
});
sum_vals.forEach((key) => {
if (!a[key]) a[key] = 0;
a[key] += v[key];
});
return a;
},{});
};
arr
containing the data
sum_vals
array with all props you want do be summed
pivot_vals
nested array with the props which should be linked
I wans't sure what to do with the type, since it is a string it can`t be summed. Did you want to count the amount of types ?
let arr = [
{
product: "Jam",
calorie: 2000,
A: 300,
B: 500,
type: "Daily",
},
{
product: "Sugar",
calorie: 1000,
A: 100,
B: 200,
type: "Daily",
},
];
let sum_vals = ["A","B"]
let pivot_vals = [["product", "calorie"]];
const func = (arr, pivot_vals, sum_vals) => {
return arr.reduce((a, v) => {
pivot_vals.forEach((pivot) => {
a[v[pivot[0]]] = v[pivot[1]];
});
sum_vals.forEach((key) => {
if (!a[key]) a[key] = 0;
a[key] += v[key];
});
return a;
},{});
};
console.log(func(arr, pivot_vals, sum_vals));

Related

Merge Objects in a array and increase count

[{name:"abc",value:5},{name:"abc",value:10},{name:"abc1",value:5},{name:"abc1",value:15}]
I want to merge it by name so that the new array will be
[{name:"abc",value:15},{name:"abc1",value:20}]
Can i do it with es6 or a simple function
Using reduce and without find or findIndex
const data = [{name:"abc",value:5},{name:"abc",value:10},{name:"abc1",value:5},{name:"abc1",value:15}];
const summedDataObj = data.reduce((acc, entry) => {
if (acc[entry.name]) acc[entry.name].value += entry.value;
else acc[entry.name] = entry;
return acc;
}, {});
const summedDataArr = Object.values(summedDataObj);
console.log(summedDataArr);
We can do it via Array.reduce()
let data = [{name:"abc",value:5},{name:"abc",value:10},{name:"abc1",value:5},{name:"abc1",value:15}]
let result = data.reduce((a,{name,value}) => {
let obj = a.find(e => e.name === name)
if(obj){
obj.value += value
}else{
a.push({name,value})
}
return a
},[])
console.log(result)
you can group the data by name using this function:
function groupBy(arr, prop) {
const map = new Map(Array.from(arr, obj => [obj[prop], []]));
arr.forEach(obj => map.get(obj[prop]).push(obj));
return Array.from(map.values());
}
this yields this result:
[
[
{"name": "abc", "value": 5},
{"name": "abc", "value": 10}
],
[
{"name": "abc1", "value": 5},
{"name": "abc1", "value": 15}
]
]
which can be aggregated by using reduce on each resulting array:
groupedData.map(entry=>entry.reduce((acc,cur)=>({
...acc,
value: acc.value + cur.value
})))
so all together we get:
function groupBy(arr, prop) {
const map = new Map(Array.from(arr, obj => [obj[prop], []]));
arr.forEach(obj => map.get(obj[prop]).push(obj));
return Array.from(map.values());
}
const data = [{name:"abc",value:5},{name:"abc",value:10},{name:"abc1",value:5},{name:"abc1",value:15}]
const aggregatedData = groupBy(data,"name")
.map(entry=>entry.reduce((acc,cur)=>({
...acc,
value:acc.value+cur.value
})))
const obj = [{name:"abc",value:5},{name:"abc",value:10},{name:"abc1",value:5},{name:"abc1",value:15}]
arr = obj.reduce((obj, item) => {
let find = obj.find(i => i.name === item.name && i.date === item.date);
let _d = {
...item
}
find ? (find.value += item.value ) : obj.push(_d);
return obj;
}, [])
console.log(arr);
const data = [{
name: "abc",
value: 5
},
{
name: "abc",
value: 10
},
{
name: "abc1",
value: 5
},
{
name: "abc1",
value: 15
},
];
const groupArr = data.reduce((r, a) => {
const idx = r.findIndex((el) => el.name === a.name);
idx === -1 ? r.push(a) : (r[idx].value += a.value);
return r;
}, []);
console.log(groupArr);
You can achieve this with the help of Array#reduce method.
Live Demo :
const arr = [{name:"abc",value:5},{name:"abc",value:10},{name:"abc1",value:5},{name:"abc1",value:15}];
const res = arr.reduce((obj, curr) => {
if (obj.hasOwnProperty(curr.name) && obj[curr.name].name === curr.name) {
obj[curr.name].value += curr.value
} else {
obj[curr.name] = curr;
}
return obj
}, {});
console.log(Object.values(res));

Object Assign values from array rather than hard code

I am trying to group data by multiple properties and sum their values.
Here is what I tried as per this question
I had a follow up to this question:
const arr = [{"shape":"square","color":"red","used":1,"instances":1},{"shape":"square","color":"red","used":2,"instances":1},{"shape":"circle","color":"blue","used":0,"instances":0},{"shape":"square","color":"blue","used":4,"instances":4},{"shape":"circle","color":"red","used":1,"instances":1},{"shape":"circle","color":"red","used":1,"instances":0},{"shape":"square","color":"blue","used":4,"instances":5},{"shape":"square","color":"red","used":2,"instances":1}];
const result = [...arr.reduce((r, o) => {
const key = o.shape + '-' + o.color;
const item = r.get(key) || Object.assign({}, o, {
used: 0,
instances: 0
});
item.used += o.used;
item.instances += o.instances;
return r.set(key, item);
}, new Map).values()];
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
I wanted to make this more reusable with the numerical values. In this for example, I want the
const item = r.get(key) || Object.assign({}, o, {
used: 0,
instances: 0
});
item.used += o.used;
item.instances += o.instances;
part especially to be reusable.
I got the numerical value keys in an array: let gee = ['used', 'instances'];
I am not sure how to use it with Object.assign. I tried to do this:
const result = [...arr.reduce((r, o) => {
const key = o.shape + '-' + o.color;
// console.log(o);
const item = gee.forEach(v => o[v] += o[v]);
// const item = r.get(key) || Object.assign({}, o, {
// used: 0,
// instances: 0
// });
// item.used += o.used;
// item.instances += o.instances;
return r.set(key, item);
}, new Map).values()];
But this is not working. How can I use an array for this bit of code:
const item = r.get(key) || Object.assign({}, o, {
used: 0,
instances: 0
});
item.used += o.used;
item.instances += o.instances;
If the Map object has the key, loop through the totalKeys and increment the object in the accumulator with current object's data. If it is new key, add a copy of the object to the Map
if (r.has(key)) {
const item = r.get(key)
totalKeys.forEach(k => item[k] += o[k])
} else {
r.set(key, { ...o })
}
Here's a snippet:
const arr = [{"shape":"square","color":"red","used":1,"instances":1},{"shape":"square","color":"red","used":2,"instances":1},{"shape":"circle","color":"blue","used":0,"instances":0},{"shape":"square","color":"blue","used":4,"instances":4},{"shape":"circle","color":"red","used":1,"instances":1},{"shape":"circle","color":"red","used":1,"instances":0},{"shape":"square","color":"blue","used":4,"instances":5},{"shape":"square","color":"red","used":2,"instances":1}];
function groupSum(array, totalKeys) {
const group = arr.reduce((r, o) => {
const key = o.shape + '-' + o.color;
if (r.has(key)) {
const item = r.get(key)
totalKeys.forEach(k => item[k] += o[k])
} else {
r.set(key, { ...o })
}
return r;
}, new Map);
return Array.from(group.values())
}
console.log(
groupSum(arr, ['used', 'instances'])
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
You can make it even more dynamic by providing an array of keys to group by. Create the key using the values of the object separated by a |
const key = groupKeys.map(k => o[k]).join("|");
if (r.has(key)) {
const item = r.get(key)
totalKeys.forEach(k => item[k] += o[k])
} else {
r.set(key, { ...o })
}
Here's a snippet:
const arr = [{"shape":"square","color":"red","used":1,"instances":1},{"shape":"square","color":"red","used":2,"instances":1},{"shape":"circle","color":"blue","used":0,"instances":0},{"shape":"square","color":"blue","used":4,"instances":4},{"shape":"circle","color":"red","used":1,"instances":1},{"shape":"circle","color":"red","used":1,"instances":0},{"shape":"square","color":"blue","used":4,"instances":5},{"shape":"square","color":"red","used":2,"instances":1}];
function groupSum(array, groupKeys, totalKeys) {
const group = arr.reduce((r, o) => {
const key = groupKeys.map(k => o[k]).join("|");
if (r.has(key)) {
const item = r.get(key)
totalKeys.forEach(k => item[k] += o[k])
} else {
r.set(key, { ...o })
}
return r;
}, new Map);
return Array.from(group.values())
}
console.log(
groupSum(arr, ['shape', 'color'], ['used', 'instances'])
)
You could vastly simplify the dataset too by not using the combination of array.reduce() with a map()... and instead just build your new array by looping through all elements of the original array with array.forEach().
I added your use of the gee array as being a list of numeric fields you want to have added... to include making sure they exist on every object of the result array...whether or not they existed on each of the previous objects in arr.
const arr = [{
"shape": "square",
"color": "red",
"used": 1,
"instances": 1
}, {
"shape": "square",
"color": "red",
"used": 2,
"instances": 1
}, {
"shape": "circle",
"color": "blue",
"used": 0,
"instances": 0
}, {
"shape": "square",
"color": "blue",
"used": 4,
"instances": 4
}, {
"shape": "circle",
"color": "red",
"used": 1,
"instances": 1
}, {
"shape": "circle",
"color": "red",
"used": 1,
"instances": 0,
"testProp": 1
}, {
"shape": "square",
"color": "blue",
"used": 4,
"instances": 5
}, {
"shape": "square",
"color": "red",
"used": 2,
"instances": 1
}];
let gee = ['used', 'instances', 'testProp'];
let result = [];
arr.forEach((o) => {
// Setup TempSource since not all o may have all elements in gee
let tempSource = {};
gee.forEach((key) => {
if (o.hasOwnProperty(key)) {
tempSource[key] = o[key];
} else {
tempSource[key] = 0;
}
});
// Look to see if the result array already has an object with same shape/color
const matchingObject = result.find(element => {
let returnValue = true;
returnValue &= (element.shape == o.shape);
returnValue &= (element.color == o.color);
return returnValue;
});
if (matchingObject) {
// Matching Object already exists... so increment values
gee.forEach((key) => {
matchingObject[key] += tempSource[key];
});
} else {
// Matching Object missing, so merge newObject and insert
let newObj = {};
Object.assign(newObj, o, tempSource);
result.push(newObj);
}
});
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Maybe this would be a way to go:
const arr = [{"shape":"square","color":"red","used":1,"instances":1},{"shape":"square","color":"red","used":2,"instances":1},{"shape":"circle","color":"blue","used":0,"instances":0},{"shape":"square","color":"blue","used":4,"instances":4},{"shape":"circle","color":"red","used":1,"instances":1},{"shape":"circle","color":"red","used":1,"instances":0},{"shape":"square","color":"blue","used":4,"instances":5},{"shape":"square","color":"red","used":2,"instances":1}],
nums=["used","instances"]
function summationOn(ar,cnts){ // cnts: add up counts on these properties
const grp=Object.keys(ar[0]).filter(k=>cnts.indexOf(k)<0) // grp: group over these
return Object.values(ar.reduce((a,c,t)=>{
const k=grp.map(g=>c[g]).join("|");
if (a[k]) cnts.forEach(p=>a[k][p]+=c[p])
else a[k]={...c};
return a
},{}))
}
const res=summationOn(arr,nums);
console.log(res);
re-write
Similar to #adiga I now expect the "countable" properties to be given in the array cnts. With this array I collect all other properties of the first object of input array ar into array grp. These are the properties I will group over.

Json Array compare with different length in javascript

Below code which I am using for creating the new array if the id is the same in arr1 and arr2. But doesn't work since arr1 and arr2 are different. array 1 has index and arr2 is without index. screenshot for your reference. Can someone help?
Note: ID in arr1 is the same as EmpId in arr2
for(let i=0; i<arr1.length; i++) {
merged.push({
...arr1[i],
...(arr2.find((itmInner) => itmInner.id === arr1[i].id))}
);
}
console.log(merged);
Array1 looks like this :
[{"Active":1,"Id":1},
{"Active":1,"Id":3},
{"Active":1,"Id":2}]
Array2 looks something like this:
Below is the sample code on how I am framing array 2:
renderElement(activity){
var arr2 = [] ;
for(var i = 0; i < activity.length; i++) {
obj = activity[i];
if(obj.Id == 28){
fetch(geturl)
.then(function (response) {
return response.json();
})
.then(function (data) {
res = data;
arr2.push(res)
})
}
else{
// Do nothing
}
}
return arr2
}
Calling Render method like below:
outputarray = currentComponent.renderElement(activity);
console.log('output', outputarray)
Expected Output:
[{"Active":1,"Id":1,"Param1": true},
{"Active":1,"Id":3}, / Keep it as such if nothing exists in other array
{"Active":1,"Id":2, "Param2": false}]
You can try this approach instead:
Example #1
const arr1 = [
{ "Active":1, "Id":1 },
{ "Active":1, "Id":3 },
{ "Active":1, "Id":2 }
];
const arr2 = [
{
0: [
{
EmpId1: 1, Param1: true
}
]
},
{
1: [
{
EmpId2: 2,Param2: false
}
]
},
{
2: [
{
EmpId3: 2
}
]
},
];
const response = arr1
.reduce((acc, value) => {
const secondaryData = arr2.map((val, index) => {
const { [`EmpId${index + 1}`]: Id, ...others } = val[Object.keys(val)][0];
return { Id, ...others };
});
const match = secondaryData.findIndex(({ Id }) => Id === value.Id);
if (match >= 0) acc.push({...value, ...secondaryData[match]})
else acc.push(value);
return acc;
}, []);
console.log(response);
Example #2
const arr1 = [
{ "Active":1, "Id":1 },
{ "Active":1, "Id":3 },
{ "Active":1, "Id":2 }
];
const arr2 = [
[
{
EmpId1: 1,
Param1: true
}
],
[
{
EmpId2: 2,
Param2: false
}
],
[
{
EmpId3: 2
}
],
]
const response = arr1
.reduce((acc, value) => {
const secondaryData = arr2.map(([val], index) => {
const { [`EmpId${index + 1}`]: Id, ...others } = val;
return { Id, ...others };
});
const match = secondaryData.findIndex(({ Id }) => Id === value.Id);
if (match >= 0) acc.push({...value, ...secondaryData[match]})
else acc.push(value);
return acc;
}, []);
console.log(response);
Basically you can create a hash map by a object property and join on that property all the arrays, i.e. reduce an array of arrays into a result object, then convert the object's values back to an array. Since each array is reduced this means each array is only traversed once O(n) and the map object provides constant time O(1) lookup to match objects. This keeps the solution closer to O(n) rather than other solutions with a nested O(n) findIndex search, which yields a solution closer to O(n^2).
const mergeByField = (...arrays) => {
return Object.values(
arrays.reduce(
(result, { data, field }) => ({
...data.flat().reduce(
(obj, el) => ({
...obj,
[el[field]]: {
...obj[el[field]],
...el
}
}),
result
)
}),
{}
)
);
};
Load each array into a payload object that specifies the field key to match on. This will return all fields used to match by, but these can safely be ignored later, or removed, whatever you need. Example:
mergeByField(
{ data: arr1, field: "Id" },
{ data: arr2, field: "EmpId" },
);
const arr1 = [
{
Active: 1,
Id: 1
},
{
Active: 1,
Id: 2
},
{
Active: 1,
Id: 3
}
];
const arr2 = [[{ EmpId: 1, Param1: true }], [{ EmpId: 3, Param2: false }]];
const mergeByField = (...arrays) => {
return Object.values(
arrays.reduce(
(result, { data, field }) => ({
...data.flat().reduce(
(obj, el) => ({
...obj,
[el[field]]: {
...obj[el[field]],
...el
}
}),
result
)
}),
{}
)
);
};
console.log(
mergeByField({ data: arr1, field: "Id" }, { data: arr2, field: "EmpId" })
);

How to flatten array in JS?

I have a data that is like following:
const data = [{
ratings: [ { rating: 5 } ],
counts: [ { count: 100 } ],
}];
And I want to flatten it in a sense that I want to get rid of arrays and have only objects, and end result to be:
const data = {
ratings: { rating: 5 },
counts: { count: 100 },
};
I tried to do something like this, but it is wrong and I believe I'm kind of over complicating it.
const flatten = data => {
return data.reduce((r, { ...children }) => {
Object.assign(children, r);
if (children) Object.assign(flatten(...Object.values(children)), r);
return r;
}, {})
}
Any ideas?
You could create recursive function with reduce method to turn all arrays to objects assuming you have just objects in those arrays.
const data = [{ratings: [ { rating: 5 } ],counts: [ { count: 100 } ]}];
function flatten(arr) {
return arr.reduce((r, e) => {
const obj = Object.assign({}, e);
for (let p in obj) {
if (Array.isArray(obj[p])) {
obj[p] = flatten(obj[p])
}
}
return Object.assign(r, obj)
}, {})
}
console.log(flatten(data))
If by any chance the data is result from JSON.parse :
var json = JSON.stringify( [{ratings:[{rating: 5}], counts:[{count: 100}]}] )
var result = JSON.parse(json, (k, v) => v[0] || v)
console.log( result )
Please check:
var data = [{ratings: [ { rating: 5 } ], counts: [ { count: 100 } ]}];
var flatten = function(data) {
if (Array.isArray(data)) {
data = data[0];
for (var key in data) data[key] = flatten(data[key]);
}
return data;
}
console.log(flatten(data));
Please check # CodePen
https://codepen.io/animatedcreativity/pen/842e17d2b9f83bc415513f937fc29be8

JavaScript - build a tree data structure recursively

I have a function called tree, which takes array of objects (as data fields from a database) and array of strings for keys. The function loops through rowsArray and recursively creates object with nested properties based on keyArray.
const tree = (rowsArray, keysArray) => {
return rows.reduce((acc, row) => {
const groupBy = (row, keys,) => {
const [first, ...rest] = keys;
if (!first) return [row];
return {
[row[first]]: groupBy(row, rest),
}
};
acc = {...groupBy(row, keys), ...acc};
return acc;
}, {});
}
The data is following:
const data = [{
ID: 1,
Main: "Financial",
Sub: "Forecasts",
Detail: "General"
}, {
ID: 2,
Main: "Financial",
Sub: "HR",
Detail: "Headcount"
}];
const result1 = tree(data, ["Main", "Sub", "Detail"]);
console.log(result1);
When I log the result, I get:
/*
// actual output
{
Financial: {
Forecasts: {
General: [Array]
}
}
}
Whereas, I would like to get following:
// expected
{
Financial: {
Forecasts: {
General: [Array]
},
HR: {
Headcount: [Array]
}
}
}
*/
The problem is, that acc variable in main function gets overridden and I get new object, instead of accumulative and I am not quite sure how to recursively build this object. I tried to pass instances of acc to groupBy function (to remember previous results), but no luck.
Do you have any idea how I could rewrite tree function or groupBy function to accomplish my goal? Thanks!
You could do it like this:
function tree(rows, keys) {
return rows.reduce( (acc, row) => {
keys.reduce( (parent, key, i) =>
parent[row[key]] = parent[row[key]] || (i === keys.length - 1 ? [row] : {})
, acc);
return acc;
}, {});
}
const data = [{ID: 1,Main: "Financial",Sub: "Forecasts",Detail: "General"}, {ID: 2,Main: "Financial",Sub: "HR", Detail: "Headcount" }];
const result1 = tree(data, ["Main", "Sub", "Detail"]);
console.log(result1);
Be aware that the spread syntax makes a shallow copy. Instead, in this solution, the accumulator is passed to the inner reduce. And so we actually merge the new row's hierarchical data into the accumulator on-the-spot.
The problem is your merge function is not deep. When you assign the values to the accumulator you overwrite existing properties - in this case Financial.
I included a deep merge function from here and now it works.
I also fixed some reference errors you had:
rows => rowsArray
keys = keysArray
// deep merge function
function merge(current, update) {
Object.keys(update).forEach(function(key) {
// if update[key] exist, and it's not a string or array,
// we go in one level deeper
if (current.hasOwnProperty(key) &&
typeof current[key] === 'object' &&
!(current[key] instanceof Array)) {
merge(current[key], update[key]);
// if update[key] doesn't exist in current, or it's a string
// or array, then assign/overwrite current[key] to update[key]
} else {
current[key] = update[key];
}
});
return current;
}
const tree = (rowsArray, keysArray) => {
return rowsArray.reduce((acc, row) => {
const groupBy = (row, keys, ) => {
const [first, ...rest] = keys;
if (!first) return [row];
return {
[row[first]]: groupBy(row, rest),
}
};
acc = merge(groupBy(row, keysArray), acc);
return acc;
}, {});
}
const data = [{
ID: 1,
Main: "Financial",
Sub: "Forecasts",
Detail: "General"
}, {
ID: 2,
Main: "Financial",
Sub: "HR",
Detail: "Headcount"
}];
const result1 = tree(data, ["Main", "Sub", "Detail"]);
console.log(result1);
You could iterate the keys and take either an object for not the last key or an array for the last key and push then the data to the array.
const tree = (rowsArray, keysArray) => {
return rowsArray.reduce((acc, row) => {
keysArray
.map(k => row[k])
.reduce((o, k, i, { length }) => o[k] = o[k] || (i + 1 === length ? []: {}), acc)
.push(row);
return acc;
}, {});
}
const data = [{ ID: 1, Main: "Financial", Sub: "Forecasts", Detail: "General" }, { ID: 2, Main: "Financial", Sub: "HR", Detail: "Headcount" }];
const result1 = tree(data, ["Main", "Sub", "Detail"]);
console.log(result1);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can iterate over the data and created a unique key based on the keys provided and then recursively generate the output structure by deep cloning.
const data = [{
ID: 1,
Main: "Financial",
Sub: "Forecasts",
Detail: "General"
}, {
ID: 2,
Main: "Financial",
Sub: "HR",
Detail: "Headcount"
}];
function generateKey(keys,json){
return keys.reduce(function(o,i){
o += json[i] + "_";
return o;
},'');
}
function merge(first,second){
for(var i in second){
if(!first.hasOwnProperty(i)){
first[i] = second[i];
}else{
first[i] = merge(first[i],second[i]);
}
}
return first;
}
function generateTree(input,keys){
let values = input.reduce(function(o,i){
var key = generateKey(keys,i);
if(!o.hasOwnProperty(key)){
o[key] = [];
}
o[key].push(i);
return o;
},{});
return Object.keys(values).reduce(function(o,i){
var valueKeys = i.split('_');
var oo = {};
for(var index = valueKeys.length -2; index >=0 ;index--){
var out = {};
if(index === valueKeys.length -2){
out[valueKeys[index]] = values[i];
}else{
out[valueKeys[index]] = oo;
}
oo = out;
}
o = merge(o,oo);
return o;
},{});
}
console.log(generateTree(data,["Main", "Sub", "Detail"]));
jsFiddle Demo - https://jsfiddle.net/6jots8Lc/

Categories