递归过滤对象数组 [英] Recursively filter array of objects
问题描述
$ p $
const input = [
{
value:' Miss1',
children:[
{value:'Miss2'},
{value:'Hit1',children:[{value:'Miss3'}]}
]
},
{
value:'Miss4',
children:[
{value:'Miss5'},
{value:'Miss6' ,子女:[{value:'Hit2'}]}
]
},
{
值:'Miss7',
children:[
{value:'Miss8'},
{value:'Miss9',children:[{value:'Miss10'}]}
]
},
{
值:'hit3',
children:[
{value:'Miss11'},
{value:'Miss12',children:[{value:'Miss13'}]}
值:'Miss14',
children:[
{value:'Hit4'},
{value :'小姐15',小孩:[{价值:'小姐16 }]}
]
},
];
在运行时,我不知道层次结构会有多深,也就是说有多少层对象将有一个儿童阵列。我已经简化了这个例子,我实际上需要匹配值的属性与搜索条件的数组。让我们暂时假设我匹配 value.includes('Hit')
。
我需要一个返回一个新数组的函数,例如:
- 每一个没有子对象的非匹配对象,或者没有匹配的子对象都不应该存在于输出对象中。
-
匹配对象的所有后代都应该保留
我正在考虑一个匹配对象是一个包含字符串 Hit $
value
的属性。 c $ c>在这种情况下,反之亦然。
输出结果应该如下所示:
const expected = [
{
value:'Miss1',
children:[
{value:'Hit1',children:[{value:'Miss3'}]}
值:'Miss4',
children:[
{value:'Miss6',children:[{value:'Hit2' }]}
]
},
{
value:'Hit3',
children:[
{value:'Miss11'},
{value:'Miss12',children:[{value:'Miss13'}]}
]
},
{
value:'Miss14',
孩子:[
{value:'Hit4'},
]
}
];
非常感谢任何花时间阅读这些内容的人,如果我到达那里,首先。
.filter()
并进行递归调用正如我在上面的评论中所描述的,基本上是你所需要的。您只需在返回之前用递归调用的结果更新每个 .children
属性。 返回值就是结果 .children $>的
.length
c $ c> collection,所以如果至少有一个,那么这个对象会被保留。
$ p $ var $ res = input.filter(function如果(o.children){
返回(o.children = o){ .children.filter(f))。length
}
})
const input = [{value:'Miss1',children:[{value:'Miss2'},{value: 'hit1',children:[{value:'Miss3'}]}],{value:'Miss4',children:[{value:'Miss5'},{value:'Miss6',children:[{value: 'Hit2'}]}]},{value:'Miss7',children:[{value:'Miss8 '},{value:'Miss9',children:[{value:'Miss10'}]}],{value:'Hit3',children:[{value:'Miss11'},{value:'Miss12', children:[{value:'Miss13'}]}],{value:'Miss14',children:[{value:'Hit4'},{value:'Miss15',children:[{value:'Miss16'}如果(o.children){return(o.children = o。)}返回true,则返回true。 children.filter(f))。length}})console.log(JSON.stringify(res,null,2))
请注意,String上的 .includes()
是ES7,所以可能需要为传统浏览器打补丁。您可以在它的位置使用传统的 .indexOf(Hit)!= -1
为了不改变原始值,创建一个map函数来复制一个对象,并在过滤器之前使用它。
返回Object.assign({,o)
}
var res = input.map(copy).filter(function如果(o.children){
返回(o.children = o){ .children.map(copy).filter(f))。length
code
为了真正挤压代码,您可以这样做:
var res = input.filter(function f(o){
return o.value.includes(Hit)||
o.children&&(o.children = o。 children.filter(f))。length
})
阅读。
Hitting a wall with this one, thought I would post it here in case some kind soul has come across a similar one. I have some data that looks something like this:
const input = [
{
value: 'Miss1',
children: [
{ value: 'Miss2' },
{ value: 'Hit1', children: [ { value: 'Miss3' } ] }
]
},
{
value: 'Miss4',
children: [
{ value: 'Miss5' },
{ value: 'Miss6', children: [ { value: 'Hit2' } ] }
]
},
{
value: 'Miss7',
children: [
{ value: 'Miss8' },
{ value: 'Miss9', children: [ { value: 'Miss10' } ] }
]
},
{
value: 'Hit3',
children: [
{ value: 'Miss11' },
{ value: 'Miss12', children: [ { value: 'Miss13' } ] }
]
},
{
value: 'Miss14',
children: [
{ value: 'Hit4' },
{ value: 'Miss15', children: [ { value: 'Miss16' } ] }
]
},
];
I don't know at run time how deep the hierarchy will be, i.e. how many levels of objects will have a children array. I have simplified the example somewhat, I will actually need to match the value properties against an array of search terms. Let's for the moment assume that I am matching where value.includes('Hit')
.
I need a function that returns a new array, such that:
Every non-matching object with no children, or no matches in children hierarchy, should not exist in output object
Every object with a descendant that contains a matching object, should remain
All descendants of matching objects should remain
I am considering a 'matching object' to be one with a value
property that contains the string Hit
in this case, and vice versa.
The output should look something like the following:
const expected = [
{
value: 'Miss1',
children: [
{ value: 'Hit1', children: [ { value: 'Miss3' } ] }
]
},
{
value: 'Miss4',
children: [
{ value: 'Miss6', children: [ { value: 'Hit2' } ] }
]
},
{
value: 'Hit3',
children: [
{ value: 'Miss11' },
{ value: 'Miss12', children: [ { value: 'Miss13' } ] }
]
},
{
value: 'Miss14',
children: [
{ value: 'Hit4' },
]
}
];
Many thanks to anyone who took the time to read this far, will post my solution if I get there first.
解决方案 Using .filter()
and making a recursive call as I described in the comment above is basically what you need. You just need to update each .children
property with the result of the recursive call before returning.
The return value is just the .length
of the resulting .children
collection, so if there's at least one, the object is kept.
var res = input.filter(function f(o) {
if (o.value.includes("Hit")) return true
if (o.children) {
return (o.children = o.children.filter(f)).length
}
})
const input = [
{
value: 'Miss1',
children: [
{ value: 'Miss2' },
{ value: 'Hit1', children: [ { value: 'Miss3' } ] }
]
},
{
value: 'Miss4',
children: [
{ value: 'Miss5' },
{ value: 'Miss6', children: [ { value: 'Hit2' } ] }
]
},
{
value: 'Miss7',
children: [
{ value: 'Miss8' },
{ value: 'Miss9', children: [ { value: 'Miss10' } ] }
]
},
{
value: 'Hit3',
children: [
{ value: 'Miss11' },
{ value: 'Miss12', children: [ { value: 'Miss13' } ] }
]
},
{
value: 'Miss14',
children: [
{ value: 'Hit4' },
{ value: 'Miss15', children: [ { value: 'Miss16' } ] }
]
},
];
var res = input.filter(function f(o) {
if (o.value.includes("Hit")) return true
if (o.children) {
return (o.children = o.children.filter(f)).length
}
})
console.log(JSON.stringify(res, null, 2))
Note that .includes()
on a String is ES7, so may need to be patched for legacy browsers. You can use the traditional .indexOf("Hit") != -1
in its place.
To not mutate the original, create a map function that copies an object and use that before the filter.
function copy(o) {
return Object.assign({}, o)
}
var res = input.map(copy).filter(function f(o) {
if (o.value.includes("Hit")) return true
if (o.children) {
return (o.children = o.children.map(copy).filter(f)).length
}
})
To really squeeze the code down, you could do this:
var res = input.filter(function f(o) {
return o.value.includes("Hit") ||
o.children && (o.children = o.children.filter(f)).length
})
Though it gets a little hard to read.
这篇关于递归过滤对象数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!