首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >在javascript中递归过滤复杂对象

在javascript中递归过滤复杂对象
EN

Stack Overflow用户
提问于 2018-10-18 05:45:19
回答 3查看 2.3K关注 0票数 1

我在这个问题上绞尽脑汁已经有一段时间了,我想也许是时候在这里发帖了。

我有一个复杂的对象结构,它可以有一个嵌套的项目属性,任何级别都可以。下面是一个示例:

代码语言:javascript
复制
 {
    resourceType: 'QuestionnaireResponse',
    item: [
      {
        linkId: 'Floors',
        answer: []
      },
      {
        linkId: 'KID',
        answer: [
          {
            valueBoolean: false
          }
        ]
      },
      {
        linkId: 'Age',
        answer: [
          {
            valueString: '≥30 Years'
          }
        ]
      },
      {
        linkId: 'UnicornGroup',
        item: [
          {
            linkId: 'DoYouLikeUnicorns',
            answer: [{valueBoolean: true}]
          },
          {
            linkId: 'DoYouLikeFHIR'
          }
        ],
        answer: []
      }
    ]
  }

我想要以如下所示的对象结束:

代码语言:javascript
复制
{
    resourceType: 'QuestionnaireResponse',
    item: [
      {
        linkId: 'KID',
        answer: [
          {
            valueBoolean: false
          }
        ]
      },
      {
        linkId: 'Age',
        answer: [
          {
            valueString: '≥30 Years'
          }
        ]
      },
      {
        linkId: 'UnicornGroup',
        item: [
          {
            linkId: 'DoYouLikeUnicorns',
            answer: [{valueBoolean: true}]
          }
        ]
      }
    ]
  }

也就是说,我希望过滤掉具有空答案数组的item对象,并且不具有具有非空答案数组的嵌套对象。

这就是我所拥有的,但它不工作:

代码语言:javascript
复制
var res = fItems.filter(function f(o) {
  if (o.answer && o.answer.length > 0) { 
    return true 
  } else {
    if(o.item){
      return f(o.item); 
    }
  }
});

我创建了一个REPL Here。我们在我们的项目中使用ramda,所以如果解决方案使用ramda,也没问题。谢谢你抽出时间来。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2018-10-18 06:56:15

我认为filter()实际上是一个错误的工具,因为它不能很容易地处理递归过滤item数组的情况。为此,您需要将items属性设置为一个新的过滤数组,并最终更改原始数组。也许一个更好的方向是通过添加你想要的项目而不是过滤来构建一个新的数组。在不是具有子项数组的组的项中,情况很简单-如果它们有答案,则只需添加这些项。然而,这些项目必须以不同的方式处理。也许像这样的东西会有所帮助:

代码语言:javascript
复制
let obj = {resourceType: 'QuestionnaireResponse',item: [{linkId: 'Floors',answer: []},{linkId: 'KID',answer: [{valueBoolean: false}]},{linkId: 'Age',answer: [{valueString: '≥30 Years'}]},{linkId: 'UnicornGroup',item: [{linkId: 'DoYouLikeUnicorns',answer: [{valueBoolean: true}]},{linkId: 'DoYouLikeFHIR'}],answer: []}]}

function filterAnswers(item_arr){
    return item_arr.reduce((arr, current) => {
        // deal with groups
        if (current.item && current.item.length){
            let item = filterAnswers(current.item)
            if (item.length) {
                let ret_obj = {linkId: current.linkId, item:item}
                arr.push(ret_obj)
            }
        }
        // deal with the simple case
        else if(current.answer && current.answer.length)
            arr.push(current)
        return arr
    }, [])
}
let filtered_items = filterAnswers(obj.item)
console.log(filtered_items)

为了保持代码简单,我假装(可能)复合组上的answers属性始终为空。从示例中还不清楚这些项是具有answers和空的item数组,还是同时具有itemanswer。无论哪种方式,在推送之前,只需测试并将其添加到对象即可。

票数 1
EN

Stack Overflow用户

发布于 2018-10-18 08:15:34

这里有一种可能性:

代码语言:javascript
复制
const filterAnswers = ({item = [], ...rest}) => {
  const items = item.map(filterAnswers).filter(
    node => (node.answer && node.answer.length)
            || (node.item && node.item.length)
  )
  return Object.assign({...rest}, items.length ? {item: items} : {})
}

const allItems = {"item": [{"answer": [], "linkId": "Floors"}, {"answer": [{"valueBoolean": false}], "linkId": "KID"}, {"answer": [{"valueString": "≥30 Years"}], "linkId": "Age"}, {"answer": [], "item": [{"answer": [{"valueBoolean": true}], "linkId": "DoYouLikeUnicorns"}, {"linkId": "DoYouLikeFHIR"}], "linkId": "UnicornGroup"}], "resourceType": "QuestionnaireResponse"}

console.log(filterAnswers(allItems))

虽然Ramda (免责声明:我是一个Ramda作者)可能会在边缘(例如filter(either(path(['answer', 'length']), path(['item', 'length']))))上有所帮助,但我相信这类问题不会轻易地变得无关紧要,而且我认为Ramda不会增加太多。

票数 1
EN

Stack Overflow用户

发布于 2018-10-18 06:20:37

我想我可以通过递归解决方案来解决这个问题。我们的想法是深入到最深层然后..。请注意此过滤器:

代码语言:javascript
复制
items.filter(i => i.answer || (i.item && i.item.length > 0));

第一个条件很简单,但是我们需要考虑第二个条件,因为在修剪较低的项之后,我们有一个对于对象来说非空的项数组(即使它自己的答案数组是空的)。

代码语言:javascript
复制
let allItems = {
  resourceType: 'QuestionnaireResponse',
  item: [{
      linkId: 'Floors',
      answer: []
    },
    {
      linkId: 'KID',
      answer: [{
        valueBoolean: false
      }]
    },
    {
      linkId: 'Age',
      answer: [{
        valueString: '≥30 Years'
      }]
    },
    {
      linkId: 'UnicornGroup',
      item: [{
          linkId: 'DoYouLikeUnicorns',
          answer: [{
            valueBoolean: true
          }]
        },
        {
          linkId: 'DoYouLikeFHIR'
        }
      ],
      answer: []
    },
    {
      linkId: 'DBZGroup', // this object should complete go away too because all of its children will be removed
      item: [{
          linkId: 'DoYouLikeUnicorns',
          answer: []
        },
        {
          linkId: 'DoYouLikeFHIR'
        }
      ],
      answer: []
    }
  ]
}

function filter(items) {
  items.forEach(i => {
    if (i.item && i.item.length > 0) i.item = filter(i.item);
    if (i.answer && i.answer.length === 0) delete i.answer;
  });
  return items.filter(i => i.answer || (i.item && i.item.length > 0));
}

// make a deep copy if you don't want to mutate the original
allItems.item = filter(allItems.item);
console.log(allItems);

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/52864073

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档