Condensing an array object recursively in javascript

I have an array of objects in the following format:

{ "country": "India", "children": [ { "name": "Karnataka", "type": "State", "children": [ { "name": "", "type": "city" }, { "name": "Bangalore", "type": "city" }, { "name": "Mangalore", "type": "city" } ] }, { "name": "Kerala", "type": "State", "children": [ { "name": "", "type": "city" } ] }, { "name": "Maharashtra", "type": "State", "children": [ { "name": "Mumbai", "type": "city" }, { "name": "Pune", "type": "city" } ] } ] } 

Each object has a child element that contains the details of the element. I need to recursively iterate over a json object and delete all nodes whose name empty string to the root. For the above json format, the output should look like this:

 { "country": "India", "children": [ { "name": "Karnataka", "type": "State", "children": [ { "name": "Bangalore", "type": "city" }, { "name": "Mangalore", "type": "city" } ] }, { "name": "Kerala", "type": "State", "children": [ ] }, { "name": "Maharastra", "type": "State", "children": [ { "name": "Mumbai", "type": "city" }, { "name": "Pune", "type": "city" } ] } ] } 

How to do it in javascript, recursive use of Underscorejs.

+6
source share
6 answers

This is a recursive solution with Array#filter() .

 function filterName(a) { if (a.name) { if (Array.isArray(a.children)) { a.children = a.children.filter(filterName); } return true; } } var object = { "country": "India", "children": [{ "name": "Karnataka", "type": "State", "children": [{ "name": "", "type": "city" }, { "name": "Bangalore", "type": "city" }, { "name": "Mangalore", "type": "city" }] }, { "name": "Kerala", "type": "State", "children": [{ "name": "", "type": "city" }] }, { "name": "Maharashtra", "type": "State", "children": [{ "name": "Mumbai", "type": "city" }, { "name": "Pune", "type": "city" }] }] }; object.children.forEach(filterName); document.write("<pre>" + JSON.stringify(object, 0, 4) + "</pre>"); 
+3
source

Try the following:

 function condense(arr) { arr.children = arr.children.map(function(c) { c.children = c.children.filter(function(c1) { return c1.name; }); return c; }); return arr; } 

I repeat through the children (with map ), then it filters the child filter array. Only children with a name that is not null or empty will be saved.

Here is the jsfiddle .

+1
source

Doesn't work with underscore.js. You can do this with ES5 reduceRight and remove members that you don't need, they should be more efficient than other approaches. The next version uses recursion (which is not as efficient as sequential processing, but most likely less code), so you can nest objects as deep as you like:

 function removeEmpty(obj) { obj.children.reduceRight(function (acc, child, i) { if (!child.name) { obj.children.splice(i, 1); } else if (child.children) { removeEmpty(child); } return null; }, null); return obj; } // Test var data = { "country": "India", "children": [ { "name": "Karnataka", "type": "State", "children": [ { "name": "", "type": "city" }, { "name": "Bangalore", "type": "city" }, { "name": "Mangalore", "type": "city" } ] }, { "name": "Kerala", "type": "State", "children": [ { "name": "", "type": "city" } ] }, { "name": "Maharashtra", "type": "State", "children": [ { "name": "Mumbai", "type": "city" }, { "name": "Pune", "type": "city" } ] } ] } document.write('Original:<br>' + JSON.stringify(data) + '<br><br>' + 'Modified:<br>' + JSON.stringify(removeEmpty(data))); 
+1
source

This is very specific to your example.

Fiddle reference

 var obj = { "country": "India", "children": [{ "name": "Karnataka", "type": "State", "children": [{ "name": "", "type": "city" }, { "name": "Bangalore", "type": "city" }, { "name": "Mangalore", "type": "city" }] }, { "name": "Kerala", "type": "State", "children": [{ "name": "", "type": "city" }] }, { "name": "Maharashtra", "type": "State", "children": [{ "name": "Mumbai", "type": "city" }, { "name": "Pune", "type": "city" }] }] }; //Before document.write("BEFORE: "+JSON.stringify(obj)); //After document.write("AFTER: "+JSON.stringify(checkJSON(obj))); function checkJSON(obj) { $.each(obj.children, function(index, value) { if ($.isArray(value.children)) { $.each(value.children, function(index, value) { if (value.name == '') { delete value.name; } }); } }); return obj; } 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script> 
+1
source

This may not be the shortest path, but it works:

 obj.children = _.each(obj.children, filter); function filter(child, index, arr) { if (child && child.name === '') { // remove the ones without name arr.splice(index, 1); } else if (_.has(child, 'children')) { // remove nested children child.children = _.each(child.children, filter); // check for empty children array and remove it (if needed) /* if (child.children.length === 0) { delete child['children']; } */ } return child; } 

Fiddle: https://jsfiddle.net/gnmosu5p/2/

+1
source

I know that a recursive approach is being given, but I cannot help myself give one insert here.

 var newData = JSON.parse(JSON.stringify(data).replace(/{"name":"".+?},?/g, "")); 

where data is the originally specified object to be restructured.

It is slightly slower than the array functions, but one of the advantages of this method is to preserve the original data object, as in the case when all array methods override the original data object if you do not clone it.

+1
source

All Articles