admin管理员组文章数量:1396763
I need to filter a nested array by matching a keyword. It must return all the objects that matches the name attribute of the parent OR one of its children and filter its children too.
Example:
[
{
"name": "abc",
"children": [
{ "name": "abcd" },
{ "name": "efg" }
]
},
{
"name": "hjk",
"children": [
{ "name": "lmn" },
{ "name": "opq" }
]
},
{
"name": "xyz",
"children": [
{ "name": "lmn" },
{ "name": "abcdef" }
]
}
]
If text input is "ab", then it must return:
[
{
"name": "abc",
"children": [
{ "name": "abcd" }
]
},
{
"name": "xyz",
"children": [
{ "name": "abcdef" }
]
}
]
(It matches the parent OR at least one of the children, and returns but parent and children)
Right now, I can only filter the parents like this:
filteredArray = _.filter(array, (parent) => {
return _.includes(_.toLower(parent.name), _.toLower(filterText));
});
How can I modify this so it filters the children too?
EDIT: A parent can have empty or no children array.
I need to filter a nested array by matching a keyword. It must return all the objects that matches the name attribute of the parent OR one of its children and filter its children too.
Example:
[
{
"name": "abc",
"children": [
{ "name": "abcd" },
{ "name": "efg" }
]
},
{
"name": "hjk",
"children": [
{ "name": "lmn" },
{ "name": "opq" }
]
},
{
"name": "xyz",
"children": [
{ "name": "lmn" },
{ "name": "abcdef" }
]
}
]
If text input is "ab", then it must return:
[
{
"name": "abc",
"children": [
{ "name": "abcd" }
]
},
{
"name": "xyz",
"children": [
{ "name": "abcdef" }
]
}
]
(It matches the parent OR at least one of the children, and returns but parent and children)
Right now, I can only filter the parents like this:
filteredArray = _.filter(array, (parent) => {
return _.includes(_.toLower(parent.name), _.toLower(filterText));
});
How can I modify this so it filters the children too?
EDIT: A parent can have empty or no children array.
Share Improve this question edited Jul 25, 2018 at 8:20 David Prieto asked Jul 25, 2018 at 7:34 David PrietoDavid Prieto 2,2996 gold badges34 silver badges51 bronze badges 5-
please explain why
"name": "xyz", "children": [ { "name": "abcdef" } ]
is in filtered array? – Niladri Basu Commented Jul 25, 2018 at 7:36 - Because the child with name "abcdef" marches the input "ab", so it returns both the matching child and the parent. Tha's what I'm trying to do. – David Prieto Commented Jul 25, 2018 at 7:40
-
can
children
have nestedchildren
s? – Niladri Basu Commented Jul 25, 2018 at 7:41 - No, only the nested structure you can see on the example. – David Prieto Commented Jul 25, 2018 at 7:43
- please take a look at my solution, it uses plain JS and uses regexp as it suits here the best, also it is more readable IMO. – amankkg Commented Jul 25, 2018 at 9:21
4 Answers
Reset to default 4For every element check name and filter its children and if one of them is true, push element with filtered children to a new array
const data = [{"name": "abc", "children": [{ "name": "abcd" }, { "name": "efg" } ] }, {"name": "hjk","children": [{ "name": "lmn"}, { "name": "opq" } ]}, { "name": "xyz","children": [{ "name": "lmn"
},{"name": "abcdef" } ] }, {"name": "abc"}, {"name": "abc", children: []}];
const res = data.reduce((acc, a) => {
const ch = a.children && a.children.filter(b => b.name.includes('ab'));
if(ch && ch.length) acc.push({...a, children: ch});
else if(a.name.includes('ab')) acc.push({ name: a.name });
return acc;
}, []);
console.log(res);
There is no real need in lodash
. #nodash! Just modern vanilla JS:
const regExp = new RegExp(filterText, 'i');
const result = array.reduce((acc, { name, children = [] }) => {
const next = children.filter(child => child.name.match(regExp));
if (name.match(regExp) || next.length > 0) {
acc.push({ name, children: next });
}
return acc;
}, []);
name.match(regExp)
will return null
if substring is not found.
children = []
handles the case when parent
has no children.
Also, note that checking for sub-string using RegExp should be much faster than performing multiple transformations and lookups (e.g. toLower
, includes
).
Here is the working repl with your example.
var arrayList = [
{
"name": "abc",
"children": [
{ "name": "abcd" },
{ "name": "efg" }
]
},
{
"name": "ab",
"children": [
{ "name": "lmn" },
{ "name": "opq" }
]
},
{
"name": "jdfj",
"children": [
{ "name": "lmn" },
{ "name": "abcdef" }
]
}
];
function filterArray(arrayList, search){
return arrayList.filter((item) => {
let childrens = item.children;
if(childrens && childrens.length){
item.children = filterArray(childrens, search);
if(item.children && item.children.length){
return true;
}
}
return item.name.indexOf(search) > -1;
});
}
const filter = filterArray(arrayList, 'ab');
console.log(filter);
IMHO, you can use Array#reduce()
method to do something like this perhaps:
arr = [{"name":"abc","children":[{"name":"abcd"},{"name":"efg"}]},{"name":"hjk","children":[{"name":"lmn"},{"name":"opq"}]},{"name":"xyz","children":[{"name":"lmn"},{"name":"abcdef"}]}, {"name": "xyz"}]
var input = "ab"
filteredArr = arr.reduce((accum, ele) => {
var obj = {};
ele['children'] && ele['children'].forEach(e => {
if (e['name'].includes(ele['name']) || e['name'].includes(input)) {
obj['name'] = ele['name'];
obj['children'] ? (obj['children'].push(e)) : (obj['children'] = [], obj['children'].push(e))
}
})
if (Object.keys(obj).length > 0) accum.push(obj);
return accum;
}, [])
console.log(filteredArr);
本文标签: javascriptFilter nested array by matching keywords in both parent or childStack Overflow
版权声明:本文标题:javascript - Filter nested array by matching keywords in both parent or child - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1744144394a2592766.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论