我有以下结构的数组:
var topics = [
{
"id": 1,
"name": "topic title 1",
"sub_categories": [
{
"id": 1,
"name": "category title 1",
"indicators": [
{
"id": 1,
"name": "indicator 1",
"sub_category_id": 1
},
{
"id": 7,
"name": "indicator 7 - foo",
"sub_category_id": 1
}
]
},
{
"id": 6,
"name": "category title 6",
"indicators": [
{
"id": 8,
"name": "indicator 8",
"sub_category_id": 6
}
]
}
]
},
{
"id": 2,
"name": "topic title 2",
"sub_categories": [
{
"id": 2,
"name": "category 2",
"indicators": [
{
"id": 2,
"name": "indicator 2 - foo",
"sub_category_id": 2
}
]
},
{
"id": 4,
"name": "category 4",
"indicators": [
{
"id": 5,
"name": "indicator 5",
"sub_category_id": 4
}
]
}
]
}
];
我需要根据指标数组中name属性的值获取过滤数组,删除不匹配的指标以及带有空指标的topic和sub_categories。因此,对于foo
的输入,结果将是:
var topics = [
{
"id": 1,
"name": "topic title 1",
"sub_categories": [
{
"id": 1,
"name": "category title 1",
"indicators": [
{
"id": 7,
"name": "indicator 7 - foo",
"sub_category_id": 1
}
]
}
]
},
{
"id": 2,
"name": "topic title 2",
"sub_categories": [
{
"id": 2,
"name": "category 2",
"indicators": [
{
"id": 2,
"name": "indicator 2 - foo",
"sub_category_id": 2
}
]
}
]
}
];
我尝试使用基于其他类似SO问题的lodash方法,但所有示例在所有级别(即子级)上只有一级嵌套或相同的键。无论是回到新阵列还是改变现有阵列,我都没问题。
答案 0 :(得分:4)
以下是基于reduce
,filter
和Object.assign
的ES6解决方案:
function filterTree(topics, find) {
return topics.reduce(function (acc, topic) {
const sub_categories = topic.sub_categories.reduce(function (acc, cat) {
const indicators = cat.indicators.filter( ind => ind.name.includes(find) );
return !indicators.length ? acc
: acc.concat(Object.assign({}, cat, { indicators }));
}, []);
return !sub_categories.length ? acc
: acc.concat(Object.assign({}, topic, { sub_categories }));
}, []);
}
// sample data
const topics = [
{
"id": 1,
"name": "topic title 1",
"sub_categories": [
{
"id": 1,
"name": "category title 1",
"indicators": [
{
"id": 1,
"name": "indicator 1",
"sub_category_id": 1
},
{
"id": 7,
"name": "indicator 7 - foo",
"sub_category_id": 1
}
]
},
{
"id": 6,
"name": "category title 6",
"indicators": [
{
"id": 8,
"name": "indicator 8",
"sub_category_id": 6
}
]
}
]
},
{
"id": 2,
"name": "topic title 2",
"sub_categories": [
{
"id": 2,
"name": "category 2",
"indicators": [
{
"id": 2,
"name": "indicator 2 - foo",
"sub_category_id": 2
}
]
},
{
"id": 4,
"name": "category 4",
"indicators": [
{
"id": 5,
"name": "indicator 5",
"sub_category_id": 4
}
]
}
]
}
];
// Call the function
var res = filterTree(topics, 'foo');
// Output result
console.log(res);

.as-console-wrapper { max-height: 100% !important; top: 0; }

答案 1 :(得分:4)
您可以使用迭代和递归方法过滤给定数组,而不使用硬连线属性。
function deepFilter(array, indicator) {
return array.filter(function iter(o) {
return Object.keys(o).some(function (k) {
if (typeof o[k] === 'string' && o[k].indexOf(indicator) !== -1) {
return true;
}
if (Array.isArray(o[k])) {
o[k] = o[k].filter(iter);
return o[k].length;
}
});
});
}
var topics = [{ id: 1, name: "topic title 1", sub_categories: [{ id: 1, name: "category title 1", indicators: [{ id: 1, name: "indicator 1", sub_category_id: 1 }, { id: 7, name: "indicator 7 - foo", sub_category_id: 1 }] }, { id: 6, name: "category title 6", indicators: [{ id: 8, name: "indicator 8", sub_category_id: 6 }] }] }, { id: 2, name: "topic title 2", sub_categories: [{ id: 2, name: "category 2", indicators: [{ id: 2, name: "indicator 2 - foo", sub_category_id: 2 }] }, { id: 4, name: "category 4", indicators: [{ id: 5, name: "indicator 5", sub_category_id: 4 }] }] }];
console.log(deepFilter(topics, 'foo'));
.as-console-wrapper { max-height: 100% !important; top: 0; }
答案 2 :(得分:3)
这几乎可以用ES 5数组方法完成(IE 9 +不需要库或polyfill):
var passed = topics.filter(function(x) {
return x.subcategories.some(function(y) {
return y.indicators.some(function(z) {
return Boolean(z.name.match(/foo/));
});
});
});
虽然这是完全一次性的代码,但对于容易消化的通用解决方案而言,情况可能过于复杂(尽管我很乐意看到有人证明我错了)。
仔细查看输出后,您需要使用reduce
代替过滤器:
var passed = topics.reduce((acc, x) => {
var hasfoo = x.subcategories.reduce((accum, y) => {
var ls = y.indicators.filter(z => z.name.match(/foo/));
if (ls.length) {
accum.push(Object.assign({}, y, {indicators: ls}));
}
return accum;
}, []);
if (hasfoo.length) {
acc.push(Object.assign({}, x, {subcategories: hasfoo}));
}
return acc;
}, []);
精明的读者会注意到这里的递归模式。抽象出来是一个练习,我被挖掘出来。 Object.assign
需要为旧浏览器进行填充(尽管很简单)。
答案 3 :(得分:1)
这也将修改现有的topics
var result = topics.filter(top =>
(top.sub_categories = top.sub_categories.filter(cat =>
(cat.indicators = cat.indicators.filter(i => i.name.match(/foo/))).length)
).length
);
实施例
var topics = [{
"id": 1,
"name": "topic title 1",
"sub_categories": [{
"id": 1,
"name": "category title 1",
"indicators": [{
"id": 1,
"name": "indicator 1",
"sub_category_id": 1
}, {
"id": 7,
"name": "indicator 7 - foo",
"sub_category_id": 1
}]
}, {
"id": 6,
"name": "category title 6",
"indicators": [{
"id": 8,
"name": "indicator 8",
"sub_category_id": 6
}]
}]
}, {
"id": 2,
"name": "topic title 2",
"sub_categories": [{
"id": 2,
"name": "category 2",
"indicators": [{
"id": 2,
"name": "indicator 2 - foo",
"sub_category_id": 2
}]
}, {
"id": 4,
"name": "category 4",
"indicators": [{
"id": 5,
"name": "indicator 5",
"sub_category_id": 4
}]
}]
}];
var result = topics.filter(top => (top.sub_categories = top.sub_categories.filter(cat => (cat.indicators = cat.indicators.filter(i => i.name.match(/foo/))).length)).length);
console.log(result);

答案 4 :(得分:0)
还有一个实现。
topics.forEach(function(topic, indexTopic, indexTopicArray) {
topic.sub_categories.forEach(function(subCat, indexsubCat, arraysubCat) {
subCat.indicators = subCat.indicators.filter(indic => indic.name.includes("foo"));
if(subCat.indicators.length === 0) {
indexTopicArray[indexTopic].sub_categories.splice(indexsubCat, 1);
}})});
console.log(topics);
完整代码。
var topics = [
{
"id": 1,
"name": "topic title 1",
"sub_categories": [
{
"id": 1,
"name": "category title 1",
"indicators": [
{
"id": 1,
"name": "indicator 1",
"sub_category_id": 1
},
{
"id": 7,
"name": "indicator 7 - foo",
"sub_category_id": 1
}
]
},
{
"id": 6,
"name": "category title 6",
"indicators": [
{
"id": 8,
"name": "indicator 8",
"sub_category_id": 6
}
]
}
]
},
{
"id": 2,
"name": "topic title 2",
"sub_categories": [
{
"id": 2,
"name": "category 2",
"indicators": [
{
"id": 2,
"name": "indicator 2 - foo",
"sub_category_id": 2
}
]
},
{
"id": 4,
"name": "category 4",
"indicators": [
{
"id": 5,
"name": "indicator 5",
"sub_category_id": 4
}
]
}
]
}
];
topics.forEach(function(topic, indexTopic, indexTopicArray) {
topic.sub_categories.forEach(function(subCat, indexsubCat, arraysubCat) {
subCat.indicators = subCat.indicators.filter(indic => indic.name.includes("foo"));
if(subCat.indicators.length === 0) {
indexTopicArray[indexTopic].sub_categories.splice(indexsubCat, 1);
}})});
console.log(topics);
答案 5 :(得分:0)