I have this working code, which retrieves the names of object properties from a JS object which (unfortunately!) is out of my scope. So I cannot change how this object is built. But I want to (and do) extract the names of the properties, that are marked as true, as an array, to be able to handle this object easier.
Object:
{
group1: {
foo: true,
itemFoo: "Name of foo", // This is what I want, because foo is true
bar: false,
itemBar: "Name of bar", // I dont want this, bar is false
// ...
},
group2: {
baz: true,
itemBaz: "Name of baz", // I want this too
// ...
},
uselessProp1: "not an object",
// ...
}
Working Code:
var items = [];
for (var m in obj) {
if (typeof obj[m] == 'object') {
for (var n in obj[m]) {
if (obj[m][n] === true) {
items.push(obj[m]['item' + (n.charAt(0).toUpperCase() + n.slice(1))]);
}
}
}
}
My question is: does someone know a more elegant way of achieving this traversal with underscore.js or plain node.js or any other library? I did experiments with _.filter, but did not come up with a solution.
Something like this?
var result = [];
_.chain(obj).filter(_.isObject).each(function(t) {
_(t).each(function(val, key) {
if(val === true)
result.push(t['item' + key.charAt(0).toUpperCase() + key.substr(1)])
})
})
This is the solution I've come so far:
http://jsfiddle.net/kradmiy/28NZP/
var process = function (obj) {
var items = [];
var objectProperties = _(obj).each(function (rootProperty) {
// exit from function in case if property is not an object
if (!_(rootProperty).isObject()) return;
_(rootProperty).each(function (value, key) {
// proceed only if property is exactly true
if (value !== true) return;
var searchedKey = 'item' + (key.charAt(0).toUpperCase() + key.slice(1));
// check that parent has this property...
if (rootProperty.hasOwnProperty(searchedKey)) {
// ...and push that to array
items.push(rootProperty[searchedKey]);
}
});
});
return items;
};
I would like to point out something :
Micha’s Golden Rule
Micha Gorelick, a data scientist in NYC, coined the following rule:
Do not store data in the keys of a JSON blob.
Your JSON should use :
{//group1
groupname:"group1",
items :[
{//item1
itemcheck:true,
itemname:'itemBar'
},
...
]
},
...
If you store itemname in key. You will have problem when traversing the JSON, because your 'itemFoo' would be using 'foo'(indirectly) to get its value. Your data structure, is the problem here. Searching your JSON is tricky. Once you follow the rule, your code will be elegant automatically.