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



我有一个对象数组。每个对象都具有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属性为true的对象。我尝试过这种方法。

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))

有更好的解决方案吗?

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

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 }

这里有一个使用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; }

需要使用递归

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))

可能回答递归过滤对象数组

您可以使用.reduce():在一次通过中实现这一点

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

最新更新