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": "Poly Soundstation/Soundpoint"
}, {
"id": "23",
"parentid": "8",
"index": "2",
"text": "New Poly",
"children": [{
"id": "5",
"parentid": "0",
"text": "Device Guides",
"index": "1",
"children": [{
"id": "10",
"index": "0",
"text": "Grandstream GXP-21XX"
}, {
"id": "11",
"index": "1",
"text": "Poly Soundstation/Soundpoint"
}, {
"id": "23",
"index": "2",
"text": "New Poly"
}]
}, {
"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
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": "Poly Soundstation/Soundpoint"
}, {
"id": "23",
"parentid": "8",
"index": "2",
"text": "New Poly",
"children": [{
"id": "5",
"parentid": "0",
"text": "Device Guides",
"index": "1",
"children": [{
"id": "10",
"index": "0",
"text": "Grandstream GXP-21XX"
}, {
"id": "11",
"index": "1",
"text": "Poly Soundstation/Soundpoint"
}, {
"id": "23",
"index": "2",
"text": "New Poly"
}]
}, {
"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
Share Improve this question edited Nov 25, 2015 at 10:16 Allan Kimaina asked Nov 25, 2015 at 9:46 Allan KimainaAllan Kimaina 3572 gold badges4 silver badges11 bronze badges 10- please show us some nested data and some code you had tried. – Nina Scholz Commented Nov 25, 2015 at 9:49
- @NinaScholz i have provided the function and json object. it is working fine but it returns duplicates – Allan Kimaina Commented Nov 25, 2015 at 10:00
- If you want it to not return duplicates, please put that information in your question. – user663031 Commented Nov 25, 2015 at 10:05
- hi @torazaburo I have updated the question – Allan Kimaina Commented Nov 25, 2015 at 10:08
-
what is
isDefined(object[key]))
doing? – Nina Scholz Commented Nov 25, 2015 at 10:12
3 Answers
Reset to default 11You 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.
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": "Poly Soundstation/Soundpoint" }, { "id": "23", "parentid": "8", "index": "2", "text": "New Poly", "children": [{ "id": "5", "parentid": "0", "text": "Device Guides", "index": "1", "children": [{ "id": "10", "index": "0", "text": "Grandstream GXP-21XX" }, { "id": "11", "index": "1", "text": "Poly Soundstation/Soundpoint" }, { "id": "23", "index": "2", "text": "New Poly" }] }, { "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>');
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 :))