Finding nested categories using js underscore

This is how my data object looks like http://jsfiddle.net/303tpLtz/

As you can see here there are categories within categories that need to be considered when doing a search

So the problem is that 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 query. For example, if I need to find a restaurant that is inside Food>

Can anyone help me with Deep search function?

My convoluted jsFiddle solution :

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;
}

      

+3


source to share


1 answer


The problem with this data is that each node potentially needs to be further validated, which means you cannot neatly apply a filter to each element, since the missing elements themselves may have nested categories that you need to validate.

However, using plain javascript or alternatively using _. reduce and a bit of recursive magic , we can only get the job done with 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' }));

      

Explain:

_.reduce

allows you to view a dataset and track a progressively β€œscaled-down” data variable. In our case, we are reducing the set of categories to a new named array result

that contains only all nested categories. To make sure we check all nested categories as well, we recursively call extractCategories

and use it to add it to the minified array of results.

Finally, we are left with categories, nested or not, which we then filter based on attr

.




A more efficient 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 work, the less concise the code will be.

Comparison of the performance of all three approaches

+1


source







All Articles