5

I have a use case where there comes a JSON response from backend in the form as follows:

 [
  {
    "name": "cab",
    "child": [
      {
        "name": "def",
        "child": [
          {
            "name": "ghi",
            "power": "0.00",
            "isParent": false
          }
        ],
        "power": "1.23",
        "isParent": true
      }
    ],
    "power": "1.1",
    "isParent": true
  },
  {
    "name": "hhi",
    "child": [
      {
        "name": "hhi2",
        "child": [
          {
            "name": "hhi3",
            "power": "0.00",
            "isParent": false
          }
        ],
        "power": "1.23",
        "isParent": true
      }
    ],
    "power": "1.1",
    "isParent": true
  }
]

I need to remove all objects that has power == 0. It's easy to use filter on simple collection of arrays, but there might be cases where any n number of childs can contain n number of childs in it.

Thanks in advance!

Abhishek
  • 1,974
  • 5
  • 31
  • 67
  • 1
    Do you know what recursion is? – Patrick Motard Aug 26 '16 at 01:21
  • 2
    For your purpose is the string `"0.00"` supposed to be equal to `0`? Also, if a parent item has power 0 but its children have non-zero power should the parent (and thus all its children) be removed? – nnnnnn Aug 26 '16 at 01:21
  • @nnnnnn , 0.00 is a string and power == 0.00 should be the check. – Abhishek Aug 26 '16 at 01:23
  • @Patrick Motard, I understand recursion. But I don't want to use the loop. Tried filter, map methods but not working correctly. – Abhishek Aug 26 '16 at 01:24
  • You can't use a filter without a loop or recursion in this case. Sorry. :( – Patrick Motard Aug 26 '16 at 01:25
  • @PatrickMotard, thanks mate. Was of the idea that there might be something that I could use. Anyways, I'll try to implement through recursion as you mentioned. Thanks in advance! :) – Abhishek Aug 26 '16 at 01:27
  • Possible duplicate of [Find by key deep in a nested object](http://stackoverflow.com/questions/15523514/find-by-key-deep-in-a-nested-object) – Patrick Motard Aug 26 '16 at 01:31

3 Answers3

5

Just iterate over the arrays with a recursive function:

var json = ["JSON_HERE"];
function deleteIterator(json) {
  if(json.power == "0.00") {
    return null;
  } else if(json.child) {
    json.child = deleteIterator(json.child);
  }
  return json;
}
for(var i = 0; i < json.length; i++) {
  json[i] = deleteIterator(json[i]);
}

What this does is:

  1. Iterate over the JSON children.
  2. Check if the power is "0.00".
    • If it is, remove it (return null)
  3. Check if it has children
    • If it does, then iterate over it (go to step 2)
  4. Return the JSON element.
Jonathan Lam
  • 16,831
  • 17
  • 68
  • 94
  • [Don't use `for...in` to iterate over an array](http://stackoverflow.com/q/500504/5743988), and make sure to declare `i` so you don't create a global. – 4castle Aug 26 '16 at 01:54
  • While we're chatting about the for loop, also consider storing the json.length as a variable, so that it doesn't have to be calculated on every cycle of the loop. `for (var i = 0, len = json.length; i < len; i++)` :) – Brett East Aug 26 '16 at 02:09
2

Recursively iterate through the object, looking for child each time and filter on power === 0 or whatever your requirements are.

If you dont know how to use recursion, here is a tutorial to get you started. I really hope someone doesnt come along after me and hand you the exact solution to your problem because this is something you should be able to solve yourself once you know how to use recursion. You could also use loops but.. recursion is best.

Edit: This problem has been solved before, in a different flavor, but all the same. If you find your implementation ends up having bugs you cant figure out, please feel free to mention me in a new question and i'll try my best to help you.

Community
  • 1
  • 1
Patrick Motard
  • 2,650
  • 2
  • 14
  • 23
  • 3
    Yes it is an answer. The person wants to know how to do it. I showed him how. I'm not required to give him exact code and I think it's a bad idea to do so. We shouldn't encourage SO users to view this site as a "ask and receive code you can copy paste and never understand.". Instead give people the means to solve the problem themselves. – Patrick Motard Aug 26 '16 at 01:27
  • @patrik: Understood what you meant. Thanks again :) – Abhishek Aug 26 '16 at 01:37
1

You can iterate recursively using Array#filter with a named function expression:

var objArray = [{"name":"cab","child":[{"name":"def","child":[{"name":"ghi","power":"0.00","isParent":false}],"power":"1.23","isParent":true}],"power":"1.1","isParent":true},{"name":"hhi","child":[{"name":"hhi2","child":[{"name":"hhi3","power":"0.00","isParent":false}],"power":"1.23","isParent":true}],"power":"1.1","isParent":true}];

objArray = _.filter(objArray, function powerFilter(o) {
  if (o.power == 0) return false;
  if (o.isParent && o.child) {
    o.child = _.filter(o.child, powerFilter); // recursive call
    o.isParent = o.child.length > 0;
    if (!o.isParent) delete o.child;
  }
  return true;
});

console.log(objArray);
<script src="https://cdn.jsdelivr.net/underscorejs/1.8.3/underscore-min.js"></script>
4castle
  • 32,613
  • 11
  • 69
  • 106
  • Typo with that extra `return` statement? Also, does that callback function in the `filter()` function need to be named (convention is anonymous function, correct?) – Jonathan Lam Aug 26 '16 at 02:04
  • @LambdaNinja It must be named in order to reference it recursively. See [this answer](http://stackoverflow.com/a/38132582/5743988) for reference. What's the typo? – 4castle Aug 26 '16 at 02:19
  • You fixed the typo in your edit and I didn't realize the purpose of the name earlier. Nice solution. +1. – Jonathan Lam Aug 26 '16 at 02:22
  • @LambdaNinja Oh, whoops yes that was a typo from accidentally clicking Save Edits – 4castle Aug 26 '16 at 02:24