javascript Underscore.js findWhere 嵌套对象

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17578725/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 08:51:05  来源:igfitidea点击:

Underscore.js findWhere nested objects

javascriptunderscore.jslodash

提问by wesbos

I have an object of folders/files that looks like this:

我有一个文件夹/文件对象,如下所示:

{
  about.html : {
    path : './about.html'
  },
  about2.html : {
    path : './about2.html'
  },
  about3.html : {
    path : './about3.html'
  },
  folderName : {
    path : './folderName',
    children : {
      sub-child.html : {
        path : 'folderName/sub-child.html'
      }
    }
  }
}

And it can go 6-7 levels deep of folders having children.

它可以深入到有孩子的文件夹的 6-7 层。

I want to find the object where pathis equal to a string that I provide. Regardless of how deep it is.

我想找到路径等于我提供的字符串的对象。不管它有多深。

I'm using underscore which only does top level:

我正在使用只做顶级的下划线:

_.findWhere(files,{path:'./about2.html'}

How can I do a deep, nested search. Does underscore have something for this or do I need to build a mixin with recursion?

如何进行深入的嵌套搜索。下划线是否有此用途,或者我是否需要使用递归构建混合?

回答by dariusriggins

This isn't the prettiest code, but I tested it out and it seems to work the way you are asking. It's setup as a lodash/underscore mixin, but can be used however. Usage would be like this:

这不是最漂亮的代码,但我对其进行了测试,它似乎按照您的要求工作。它被设置为 lodash/underscore mixin,但可以使用。用法如下:

_.findDeep(testItem, { 'path': 'folderName/sub-child.html' })

Implementation:

执行:

findDeep: function(items, attrs) {

  function match(value) {
    for (var key in attrs) {
      if(!_.isUndefined(value)) {
        if (attrs[key] !== value[key]) {
          return false;
        }
      }
    }

    return true;
  }

  function traverse(value) {
    var result;

    _.forEach(value, function (val) {
      if (match(val)) {
        result = val;
        return false;
      }

      if (_.isObject(val) || _.isArray(val)) {
        result = traverse(val);
      }

      if (result) {
        return false;
      }
    });

    return result;
  }

  return traverse(items);

}

回答by McGarnagle

Instead of findWhere, use filter, which takes a function as the predicate rather than a key-value map. Use a recursive function to check the current node and possible children. Something like this:

而不是findWhere,使用filter,它将函数作为谓词而不是键值映射。使用递归函数检查当前节点和可能的子节点。像这样的东西:

var searchText = './about2.html';

var recursiveFilter = function(x) {
    return x.path == searchText || 
        ( typeof x.children != 'undefined' && recursiveFilter(x.children['sub-child.html']) );
};

_.filter(files, recursiveFilter);


Edit

编辑

Assuming this works, you'll probably want to make a function getRecursiveFilter(searchText). Here's how that would look:

假设这有效,您可能想要创建一个 function getRecursiveFilter(searchText)。这是它的样子:

function getRecursiveFilter(searchText) { 
    var recursiveFilter = function(x) {
        return x.path == searchText || 
            (typeof x.children != 'undefined' 
                && arguments.callee(x.children['sub-child.html']) );
    };
    return  recursiveFilter;
}

Note that here, recursiveFilteruses arguments.calleeto call itself recursively.

注意这里,recursiveFilter用于arguments.callee递归调用自身



Here's a working demo.

这是一个工作演示。

回答by abenrob

This already has an accepted answer, but this other answer was very clean and perfect for my similar situation: https://stackoverflow.com/a/21600748/1913975_.filter+_.where

这已经有一个可以接受的答案,但另一个答案对于我的类似情况非常干净和完美:https: //stackoverflow.com/a/21600748/1913975_.filter+_.where

回答by adhiroha

Though accepted answer works, it's too generic - it searches all the properties of an object to find children. I am proposing introducing an extra parameter, called 'recursProperty' which will be considered to go deep in the object. This solution is also setup to be used as lodash/underscore mixin and extends loadash/underscore capabilities.

尽管接受的答案有效,但它太通用了 - 它搜索对象的所有属性以查找子项。我提议引入一个名为“recursProperty”的额外参数,它将被视为深入对象。此解决方案还设置为用作 lodash/underscore mixin 并扩展 loadash/underscore 功能。

_.findDeep = function(collection, predicate, recursProperty){
    let items = [];
    _.each(collection, each => items.push(each));
    return _.find(items, function(value, key, coll){
        if (predicate(value, key, coll)){
            return true;
        } else {
            _.each(value[recursProperty], each => items.push(each));
        }
    });
};

It can be used as any other underscore function. e.g,

它可以用作任何其他下划线函数。例如,

_.findDeep(self.baseEntities, baseEntity => baseEntity.id === 71, 'entity');

Not providing proper value for 'recursProperty' argument or providing null/undefined will simply make the search only on first level (no going deep).

不为 'recursProperty' 参数提供适当的值或提供 null/undefined 只会使搜索仅在第一级(不会深入)。