Stack Overflow is a community of 4.7 million programmers, just like you, helping each other.

Join them; it only takes a minute:

Sign up
Join the Stack Overflow community to:
  1. Ask programming questions
  2. Answer and help your peers
  3. Get recognized for your expertise

I have an array of objects in the below 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"
        }
      ]
    }
  ]
}

Every object has a children element which contains the details of the element. I need to recursively iterate through the json object and remove all the nodes whose name is empty string up till the root. For the above json format, the output should be like below:

{
  "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 this in javascript recursively using Underscorejs.

share|improve this question
    
Array#map ..? – Rayon Dabre 1 hour ago
    
@RayonDabre—seems to me reduceRight and delete unwanted members is better, but does underscore.js have that? If not there's the built–in one. – RobG 1 hour ago
    
This SO question might help you – Aides 1 hour ago

Try this:

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 iterate through the children (with map), then filter the children array with filter. Only the children with a name not null or empty will be kept.

Here is a jsfiddle.

share|improve this answer
    
I tried similar approach. I wanted to attempt this with recursion. – Pradeep 1 hour ago
    
Why ? You only have two depth levels. Furthermore, at the first level, you keep empty children, on the second one you delete them. It does not seem like a good recursion candidate. – Derlin 1 hour ago

Not au fait with underscore.js. You can do this with ES5 reduceRight and delete members that you don't want, it should be more efficient than other approaches. The following uses recursion (which isn't as efficient as serial processing but is likely less code), so you can nest the 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)));

share|improve this answer

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>");

share|improve this answer

This is very specific to your example.

Link to fiddle

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>

share|improve this answer

Probably not the shortest way, 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/

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.