[英]Filtering array based on value in deeply nested object in javascript
我有以下结构的数组:
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
}
]
}
]
}
];
我需要根据指标数组中名称属性的值获取过滤数组,删除不匹配的指标以及带有空指标的主题和子类别。 所以对于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 方法,但所有示例要么只有一层嵌套,要么在所有级别(即子项)上都有相同的键。 无论是取回新数组还是改变现有数组,我都可以。
这是一个基于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; }
您可以使用迭代和递归方法来过滤给定的数组,而无需硬连线属性。
const deepFilter = (array, indicator) => { return array.filter(function iter(o) { return Object.keys(o).some(k => { if (typeof o[k] === 'string' && o[k].includes(indicator)) { return true; } if (Array.isArray(o[k])) { o[k] = o[k].filter(iter); return o[k].length; } }); }); } 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 }] }] }]; console.log(deepFilter(topics, 'foo'));
.as-console-wrapper { max-height: 100% !important; top: 0; }
这几乎可以通过 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
而不是 filter:
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
需要为旧浏览器填充(虽然很简单)。
这也将修改现有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);
再一个实现。
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);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.