使用Underscore.js进行嵌套分类搜索

3
这是我的数据对象的样子: http://jsfiddle.net/303tpLtz/1 如您所见,在此处 https://gist.github.com/sahanDissanayake/b29c913a00d33bffc67f#file-gistfile1-js-L199 中,存在分类中的分类,必须在进行搜索时进行考虑。
因此问题是,我可以使用_.findWhere(result.response.categories, {name: 'Arts & Entertainment'}) 找到类别的顶级名称
但问题是,当我需要找到提供的请求中提到的某些内容时。例如,如果我需要找到一个在“食品 >”中的餐厅
有人可以帮我实现深度搜索功能吗?
我的解决方案: 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;
}

猜测:Underscore.js - 过滤嵌套的 Json。互联网搜索:_Underscore.js - 过滤嵌套的 Json_。还有更多的猜测。 - Ryan Vincent
不要@RyanVincent,如果你仔细看,我的类别中还有更多的JSON对象需要在搜索时考虑。https://gist.github.com/sahanDissanayake/b29c913a00d33bffc67f#file-gistfile1-js-L199 - Sahan
1个回答

1
这些数据的问题是每个节点都有可能需要进一步检查,这意味着您不能简单地对每个项应用过滤器,因为被跳过的项本身可能具有您需要检查的嵌套类别。然而,使用纯javascript或者结合_.reduce和一点递归神奇, 我们可以只用很少的代码完成工作。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' }));

解释一下:

_.reduce 让你可以遍历一组数据并跟踪一个逐渐“减少”的数据变量。在我们的情况下,我们将一组类别缩小到一个名为 result 的新数组中,该数组仅包含所有嵌套的类别。为了确保我们也检查所有嵌套的类别,我们递归调用 extractCategories 并使用它的结果将其添加到缩小的结果数组中。

最后,我们剩下的是所有的类别,无论是否嵌套,然后根据 attr 匹配进行筛选。


更高效的版本,少使用字符串连接:

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

随着我们追求更高的性能,代码变得越来越冗长。三种方法的性能比较

嘿,我正在使用lodash V2.4.1 https://github.com/lodash/lodash/blob/2.4.1/doc/README.md。 _.isMatch不在那里,还有其他什么可以用吗? - Sahan
我以为你在使用下划线... 你换了吗?无论如何,仍然可以使用 _.where_.filter 替代 _.isMatch。我更新了我的答案。 - Benny Bottema
好像我的函数比你的快得多?!?http://jsfiddle.net/a3wevt35/4/ - Sahan
似乎过滤许多小数组比过滤一个大数组更耗时。我更新了我的答案,提供了一个更短、更快的版本。它仍然比较慢。但是,除非你有性能问题,否则不要进行过早优化 - Benny Bottema
我非常担心性能问题,因为这个函数将在NodeJS服务器上执行,所以越快越好。 - Sahan
似乎连接字符串也会使过程变慢。我回到了类似于你的方法(使用_.each),但仍然应用递归。这里是三种方法的性能 - Benny Bottema

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接