11

我有一个看起来像这样的文件夹/文件对象:

{
  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'
      }
    }
  }
}

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

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

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

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

如何进行深度嵌套搜索。underscore 是否有此功能,或者我是否需要构建一个带有递归的 mixin?

4

4 回答 4

12

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

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

执行:

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

}
于 2013-07-10T20:10:23.163 回答
9

而不是findWhereuse 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);

编辑

假设这可行,您可能想要创建一个 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;
}

请注意,此处,recursiveFilter用于arguments.callee递归调用自身


这是一个工作演示。

于 2013-07-10T19:02:25.750 回答
6

这已经有一个公认的答案,但这个其他答案非常干净,非常适合我的类似情况:https _.filter ://stackoverflow.com/a/21600748/1913975 +_.where

于 2014-05-01T18:27:00.560 回答
1

尽管公认的答案有效,但它太通用了——它搜索对象的所有属性以查找子对象。我建议引入一个额外的参数,称为“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));
        }
    });
};

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

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

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

于 2018-04-18T06:32:46.367 回答