This is how my data object would look like http://jsfiddle.net/303tpLtz/1
As you may see here there are categories inside categories which must be considered when the search is done
So the problem is I can find the top level names of the categories using _.findWhere(result.response.categories, {name: 'Arts & Entertainment'})
But the problem is when I need to find something mentioned inside the supplied request, For example if I need to find a restaurant which is inside Food >
Can anyone help me with the Deep search function please ?
My tangled solution jsFiddle:
function findDeep(cats, attrs) {
_.each(cats, function(data, i) {
var copy = data;
// delete copy.categories;
newArr.push(copy);
_.each(data.categories, function(newObj) {
var copy2 = newObj;
// delete copy2.categories;
newArr.push(copy2)
if (newObj.categories) {
_.each(newObj.categories, function(otherObj) {
var copy3 = otherObj;
// delete copy3.categories;
newArr.push(copy3)
})
}
})
});
return _.findWhere(newArr, attrs) || null;
}
The problem with this data is each node potentially should be inspected further, which means you can't neatly apply a filter to every item, because the skipped items themselves might have nested categories you need to inspect.
However, using plain javascript or alternatively with the help of _.reduce and a bit of recursive magic, we can get the job done with only a little bit of code.
jsFiddle
function findMatchingCategories(cats, attrs) {
return _.filter(extractCategories(cats), attrs);
function extractCategories(cats) {
return _.reduce(cats, function (result, value) {
return result.concat([value]).concat(value.categories ? extractCategories(value.categories) : []);
}, []);
}
}
console.log(findMatchingCategories(data, { name: 'Tunnel' }));
To explain:
_.reduce let's you go through a set of data and keep track of a progressively 'reduced' data variable. In our case, we reduce a set of categories to a new array called result which only contains all nested categories. To make sure we inspect all nested categories as well, we recursively call extractCategories and use it's result to add it to the reduced result array.
Finally what we are left with are all categories, nested or not, which we then filter based on attr matches.
A more performant version with less concatenation:
jsFiddle
function findMatchingCategories(cats, attrs) {
return _.filter(extractCategories(cats, []), attrs);
function extractCategories(currentCats, allCats) {
_.each(currentCats, function (value) {
allCats.push(value);
if (value.categories) {
extractCategories(value.categories, allCats);
}
}, []);
return allCats;
}
}
console.log(findMatchingCategories(data, { name: 'Tunnel' }));
The more we go for performance, the less concise the code becomes.
Performance comparison of all three approaches
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With