如何基于对象数组中的属性进行多级过滤

时间:2021-07-15 20:34:33

标签: javascript

我有一个对象数组。每个对象都有 hasPermission 属性和 children 属性。 children 属性也是一个对象数组,每个对象都有 hasPermission 属性。 我的数组是这样的:

const navigationMenus = [
  {
    hasPermission: false,
    name: 'Main',
    type: 'section',
    children: [
      {
        hasPermission: true,
        name: 'Test',
        type: 'item',
        link: '/test'
      }
    ]
  },
  {
    hasPermission: true,
    name: 'Master',
    type: 'section',
    children: [
      {
        hasPermission: true,
        name: 'Operator Group',
        type: 'item',
        link: '/operator-group'
      },
      {
        hasPermission: false,
        name: 'Operation Group',
        type: 'item',
        link: '/operation-group'
      }
    ]
  }
];

基于 hasPermission 属性,我想要另一个数组,它只包含 hasPermission 属性为真的那些对象。 我尝试过这种方法。

const permittedNavigationMenus = []
for (let i = 0; i < navigationMenus.length; i++) {
  const section = navigationMenus[i];
  if (section.hasPermission) {
    const permittedSection = {
      name: section.name,
      type: section.type,
      children: []
    }
    for (let j = 0; j < section.children.length; j++) {
      const item = section.children[j]
      if (item.hasPermission) {
        permittedSection.children.push(item)
      }
    }
    permittedNavigationMenus.push(permittedSection)
  }
}
console.log(JSON.stringify(permittedNavigationMenus, null, 2))

有没有更好的解决方案?

4 个答案:

答案 0 :(得分:1)

一个简单的递归函数就可以做到:

const navigationMenus = 
  [ { hasPermission: false, name: 'Main', type: 'section', children: 
      [ { hasPermission: true, name: 'Test', type: 'item', link: '/test' } ] 
    } 
  , { hasPermission: true, name: 'Master', type: 'section', children: 
      [ { hasPermission: true, name: 'Operator Group', type: 'item', link: '/operator-group' } 
      , { hasPermission: false, name: 'Operation Group', type: 'item', link: '/operation-group' } 
  ] } ] 

const navigationMenusTrue = []

function runArray(arr,parent)
  {
  arr.forEach(({children,...info}) => 
    {
    if (info.hasPermission)
      {
      let newRow = {...info}
      parent.push(newRow)
      if (children)
        {
        let xChilds = []
        newRow.children = xChilds
        runArray(children,xChilds)
        }
      }  
    })
  }

runArray(navigationMenus,navigationMenusTrue)

console.log( navigationMenusTrue )
.as-console-wrapper {max-height: 100%!important;top:0 }

答案 1 :(得分:1)

这是一个使用 Array#reduce()

的递归选项

const
  filterByPermission = (arr) => {
    return arr.reduce((a, o) => {
      if (o.hasPermission) {
        const _o = o?.children?.length
          ? { ...o, children: filterByPermission(o.children) }
          : { ...o };
        a.push(_o);
      }

      return a;
    }, [])
  },

  navigationMenus = [{ hasPermission: false, name: 'Main', type: 'section', children: [{ hasPermission: true, name: 'Test', type: 'item', link: '/test' }] }, { hasPermission: true, name: 'Master', type: 'section', children: [{ hasPermission: true, name: 'Operator Group', type: 'item', link: '/operator-group' }, { hasPermission: false, name: 'Operation Group', type: 'item', link: '/operation-group' }] }],
  result = filterByPermission(navigationMenus);

console.log(result)
.as-console-wrapper { max-height: 100% !important; top: 0; }

答案 2 :(得分:1)

需要使用递归

const navigationMenus = [
  {
    hasPermission: false,
    name: 'Main',
    type: 'section',
    children: [
      {
        hasPermission: true,
        name: 'Test',
        type: 'item',
        link: '/test'
      }
    ]
  },
  {
    hasPermission: true,
    name: 'Master',
    type: 'section',
    children: [
      {
        hasPermission: true,
        name: 'Operator Group1',
        type: 'item',
        link: '/operator-group'
      },
      {
        hasPermission: false,
        name: 'Operation Group2',
        type: 'item',
        link: '/operation-group',
        children: [
          {
            hasPermission: true,
            name: 'Operator Group3',
            type: 'item',
            link: '/operator-group'
          },
          {
            hasPermission: false,
            name: 'Operation Group4',
            type: 'item',
            link: '/operation-group'
          }
    ]
      }
    ]
  }
];

function filterRec(arr = []) {
    return arr.map(el => {
        const elem = el.hasPermission && el
        const children = filterRec(el.children)

        const result = ({ ...elem, ...(children.length && ({children}) || {}) })
        return Object.keys(result).length && result
    }).filter(Boolean)
}

   // or without empty children key
// /function filterRec(arr = []) {
// return arr.reduce((acc, el) => {
//     let result = el.hasPermission && el

//     const children = filterRec(el.children)
//     if (result && children.length) {
//         result.children = children
//     } else if (!result) {
//         result = children
//     }

//     return acc.concat(result).filter(Boolean)
// }, [])
// }
console.log(filterRec(navigationMenus))

可能回答Recursively filter array of objects

答案 3 :(得分:0)

您可以使用 .reduce() 一次性完成:

const permittedNavigationMenus = navigationMenus.reduce(
  (acc, cur) => {
    if (cur.hasPermission) {
      acc.push({
        ...cur,
        children: cur.children.filter(({ hasPermission }) => hasPermission)
      })
    }

    return acc;
  },
  []
);