递归过滤对象数组 [英] Recursively filter array of objects

查看:167
本文介绍了递归过滤对象数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

打这个墙壁,以为我会在这里张贴,以防万一某种灵魂遇到类似的。我有一些这样的数据:

$ 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆