How to split an javascript array of an object with a specific condition using lodash / underscorejs

I have an array of such objects:

var data = [ { type : "parent", name : "A" }, { type : "child", name : "1" }, { type : "child", name : "2" }, { type : "parent", name : "B" }, { type : "child", name : "3" } ] 

and I want to move the child objects to the parent objects divided by the parrent object (there is no specified key from the child object belonging to that partin). Thus, it is shared only by the parent. To be simple, I want to change the array to:

 [ { type : "parent", name : "A", child: [ { type : "child", name : "1" }, { type : "child", name : "2" } ] }, { type : "parent", name : "B", child: [ { type : "child", name : "3" } ] } ] 

I read lodash about chunk , but it's useless.

+5
source share
5 answers

You can use either the built-in function Array.prototype.reduce or lodash reduce :

 var data = [ { type : "parent", name : "A" }, { type : "child", name : "1" }, { type : "child", name : "2" }, { type : "parent", name : "B" }, { type : "child", name : "3" } ]; // If using _.reduce then use: // var newData = _.reduce(data, function(arr, el) {...}, []); var newData = data.reduce(function(arr, el) { if (el.type === 'parent') { // If el is pushed directly it would be a reference // from the original data object arr.push({type: el.type, name: el.name, child: []}); } else { arr[arr.length - 1].child.push({type: el.type, name: el.name}); } return arr; }, []); 
+8
source

Here's a lodash solution that might be a little easier to understand. Codepen

A few notes:

  • this changes the incoming data object - if this is a problem, we can throw some calls to _.clone() .
  • This will only work if each parent has 26 or fewer children due to the name: "ab" template you selected
 var lastParent; var result = _.chain(data) .groupBy(function (item) { if (item.type === 'parent') lastParent = item.name return lastParent }) .map(function (group) { var parent = _.first(group) parent.child = _.chain(group) .slice(1) .map(function (child, index) { child.name = parent.name.toLowerCase() + String.fromCharCode(index + 97) return child }) .value() return parent }) .value() console.log(result) 
+2
source

Normal javascript version:

 var newArr = []; var j=0; var k=0; for (var i = 0; i <data.length; i++) { if(data[i].type == 'parent'){ newArr[j] = data[i]; newArr[j].children = []; j++; k=0; } else { data[i].name = newArr[j-1].name.toLowerCase() + String.fromCharCode(k + 97) newArr[j-1].children[k] =data[i]; k++; } } console.log(newArr) 

I assume that the parent is always placed in front of the children, as indicated in your example data.

It would also be nice if you could prevent parents with 26 children. This will make String.fromCharCode(k + 97) print strange characters. For this, see http://www.asciitable.com/

0
source
 for (ele in data) { if (!data[ele].hasOwnProperty('child') && data[ele].type=='parent') { data[ele].child = []; while(data[parseInt(ele) + 1] && data[parseInt(ele) + 1].type == 'child') { data[ele].child.push({type: data[parseInt(ele) + 1].type, name:data[parseInt(ele) + 1].name}); data.splice(parseInt(ele) + 1, 1); } } } console.log(data); 
0
source

Try a simple loop:

 var current, parent, result = [], i = 0; while(current = data[i++]){ if(current.type === "parent"){ current.child = []; result.push(current); parent = current }else{ current.name = (parent.name + String.fromCharCode(parent.child.length + 97)).toLowerCase(); parent.child.push(current) } } 

Demo

0
source

All Articles