Underscore.js findWhere вложенные объекты
У меня есть объект папок/файлов, который выглядит так:
{
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'}
Как сделать глубокий, вложенный поиск. У подчеркивания есть что-то для этого или мне нужно создать mixin с рекурсией?
Ответы
Ответ 1
Это не самый красивый код, но я тестировал его и, похоже, работал так, как вы просите. Он настраивается как смесь lodash/underscore, но может использоваться. Использование будет таким:
_.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);
}
Ответ 2
Вместо findWhere
используйте filter
, который принимает функцию как предикат, а не карту значения ключа. Используйте рекурсивную функцию для проверки текущего node и возможных детей. Что-то вроде этого:
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);
Изменить
Предполагая, что это работает, вы, вероятно, захотите сделать функцию 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
для рекурсивного вызова.
Здесь рабочая демонстрация.
Ответ 3
У этого уже есть принятый ответ, но этот ответ был очень чистым и идеальным для моей подобной ситуации: fooobar.com/info/262890/...
_.filter
+ _.where