3

I need a javascript recursive function that return an array of values when key and JavaScript object is passed to this function.

Note that the nested JavaScript object has unknown depth. The function is working fine but it returns duplicates.

   function getValuesByKey(object, key) {
    var values = [];
    recursiveFx(object);
    function recursiveFx(object) {
      for (var property in object) {
        if (object.hasOwnProperty(property)) {
          if (typeof object[property] == "object") {
           recursiveFx(object[property]);
          } else {
            //found a property which is not an object
            try {
              if (isDefined(object[key])) {
                console.log('Here is the value that is to be pushed',object[key]);
                values.push(object[key]);
              }
            } catch (e) {

            }
          }
        }
      }
    }
    return values;
  } 

Here is the isDefined helper function

function isDefined(variable) {
    try {
    if (typeof(variable) !== 'undefined') return true;
    } catch (e) {
      return false;
    }
  }

Here is an example of JavaScript object:

{
      "children": [{
        "id": "5",
        "parentid": "0",
        "text": "Device Guides",
        "index": "1",
        "children": [{
          "id": "10",
          "index": "0",
          "text": "Grandstream GXP-21XX"
        }, {
          "id": "11",
          "index": "1",
          "text": "Polycom Soundstation/Soundpoint"
        }, {
          "id": "23",
          "parentid": "8",
          "index": "2",
          "text": "New Polycom",
          "children": [{
            "id": "5",
            "parentid": "0",
            "text": "Device Guides",
            "index": "1",
            "children": [{
              "id": "10",
              "index": "0",
              "text": "Grandstream GXP-21XX"
            }, {
              "id": "11",
              "index": "1",
              "text": "Polycom Soundstation/Soundpoint"
            }, {
              "id": "23",
              "index": "2",
              "text": "New Polycom"
            }]
          }, {
            "id": "6",
            "parentid": "0",
            "text": "Pre-Sales Evaluation",
            "index": "0",
            "children": []
          }, {
            "id": "7",
            "parentid": "0",
            "text": "Router Setup Guides",
            "index": "2",
            "children": [{
              "id": "9",
              "index": "0",
              "text": "Sonicwall"
            }, {
              "id": "12",
              "index": "1",
              "text": "Cisco"
            }]
          }]
        }, {
          "id": "6",
          "parentid": "0",
          "text": "Pre-Sales Evaluation",
          "index": "0",
          "children": []
        }, {
          "id": "7",
          "parentid": "0",
          "text": "Router Setup Guides",
          "index": "2",
          "children": [{
            "id": "9",
            "index": "0",
            "text": "Sonicwall"
          }, {
            "id": "12",
            "index": "1",
            "text": "Cisco"
          }]
        }]}]};

When I run this getValuesByKey(jsonObj, 'id'); I get the following array:

["5", "5", "5", "5", "10", "10", "10", "11", "11", "11", "23", "23", "23", "23", "5", "5", "5", "5", "10", "10", "10", "11", "11", "11", "23", "23", "23", "6", "6", "6", "6", "7", "7", "7", "7", "9", "9", "9", "12", "12", "12", "6", "6", "6", "6", "7", "7", "7", "7", "9", "9", "9", "12", "12", "12"]

Notice that 5 has been returned 4 times instead of 2 times

10
  • please show us some nested data and some code you had tried. Commented Nov 25, 2015 at 9:49
  • @NinaScholz i have provided the function and json object. it is working fine but it returns duplicates Commented Nov 25, 2015 at 10:00
  • If you want it to not return duplicates, please put that information in your question. Commented Nov 25, 2015 at 10:05
  • hi @torazaburo I have updated the question Commented Nov 25, 2015 at 10:08
  • what is isDefined(object[key])) doing? Commented Nov 25, 2015 at 10:12

3 Answers 3

11

You are checking for the presence of key each time through the loop over the object's properties. So you are getting as many values as there are properties on the object. So:

function getValuesByKey(object, key) {
  var values = [];
  recursiveFx(object);
  function recursiveFx(object) {

    if (key in object) values.push(object[key]);
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

    for (var property in object) {
      if (object.hasOwnProperty(property)) {
        if (typeof object[property] == "object") {
         recursiveFx(object[property]);
        }
      }
    }
  }
  return values;
} 

Alternative: use JSON.stringify with replacer

Anyway, you can do this more easily with

function getValuesByKey(object, key) {
  var values = [];
  JSON.stringify(object, function(k, v) { 
    if (k === key) values.push(v);
    return v;
  });
  return values;
}

This uses the replacer parameter to JSON.stringify to intercept each key value pair. The stringified value itself we don't need and throw away.

Sign up to request clarification or add additional context in comments.

5 Comments

This is not recursive.
@QuentinRoy Actually, it is.
@torazaburo I have tested both alternatives and they are working like magic.
Thanks a lot @torazaburo
@torazaburo Thanks that is what i needed
3

Just an idea of recursion:

var data = { "children": [{ "id": "5", "parentid": "0", "text": "Device Guides", "index": "1", "children": [{ "id": "10", "index": "0", "text": "Grandstream GXP-21XX" }, { "id": "11", "index": "1", "text": "Polycom Soundstation/Soundpoint" }, { "id": "23", "parentid": "8", "index": "2", "text": "New Polycom", "children": [{ "id": "5", "parentid": "0", "text": "Device Guides", "index": "1", "children": [{ "id": "10", "index": "0", "text": "Grandstream GXP-21XX" }, { "id": "11", "index": "1", "text": "Polycom Soundstation/Soundpoint" }, { "id": "23", "index": "2", "text": "New Polycom" }] }, { "id": "6", "parentid": "0", "text": "Pre-Sales Evaluation", "index": "0", "children": [] }, { "id": "7", "parentid": "0", "text": "Router Setup Guides", "index": "2", "children": [{ "id": "9", "index": "0", "text": "Sonicwall" }, { "id": "12", "index": "1", "text": "Cisco" }] }] }, { "id": "6", "parentid": "0", "text": "Pre-Sales Evaluation", "index": "0", "children": [] }, { "id": "7", "parentid": "0", "text": "Router Setup Guides", "index": "2", "children": [{ "id": "9", "index": "0", "text": "Sonicwall" }, { "id": "12", "index": "1", "text": "Cisco" }] }] }] };

function getValuesByKey(object, key) {
    var values = [];

    function r(obj) {
        Object.keys(obj).forEach(function (k) {
            if (Array.isArray(obj[k])) {
                obj[k].forEach(r);
                return;
            }
            if (typeof obj[k] === 'object') {
                r(obj[k]);
                return;
            }
            k === key && !~values.indexOf(obj[k]) && values.push(obj[k]);
        });
    }

    r(object);
    return values;
}

document.write('<pre>' + JSON.stringify(getValuesByKey(data, 'id'), 0, 4) + '</pre>');

1 Comment

this is interesting. Thanks a lot
0

Ok I got it, there is a bug in your code. You should test that key === property when testing if (isDefined(object[key])) {

Otherwise, you're just adding the matching value whenever you're examining an object that has that value in another property (if that's clear :))

1 Comment

Thanks @Jad for your help

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.