JS如何实现对象数组按id去重并合并同id项role属性为数组
数组按id去重并合并role属性实现方案
问题场景
现有如下对象数组:
const a = [ { id: 1, name: 'John', role: 'admin' }, { id: 1, name: 'John', role: 'user' }, { id: 2, name: 'Max', role: 'user' } ]
需要实现的效果:按id对重复对象去重,相同id仅保留单个实例,将同id下的role属性合并为数组,最终输出结构如下:
const a = [ { id: 1, name: 'John', role: ['admin', 'user'] }, { id: 2, name: 'Max', role: 'user' } ]
现有代码仅能处理两属性场景,无法正确保留name属性,现有实现如下:
const b = [...new Set(a.map(d => d.id))].map(obj => { return { id: obj, data: a.filter(d => d.id === obj).map(d => d.role) } })
可行实现
方案1:reduce单次遍历实现(推荐,性能更好)
核心逻辑是用累加器按id分组,分组时直接取同id第一条数据的公共属性(如name),同时收集所有role值,最后根据role的数量决定是保留字符串还是数组格式:
const res = Object.values(a.reduce((group, item) => { if (!group[item.id]) { // 初始化当前id的分组,直接保留id、name属性,role初始化为空数组 group[item.id] = { id: item.id, name: item.name, role: [] } } // 收集当前条目的role group[item.id].role.push(item.role) return group }, {})).map(groupItem => { // 单条role直接返回字符串,多条返回数组,和目标格式对齐 groupItem.role = groupItem.role.length === 1 ? groupItem.role[0] : groupItem.role return groupItem })
方案2:基于原有代码改造
如果要沿用之前的Set去重思路,只需要在遍历id时,取出同id的第一条数据的name属性即可,小数据量下也能正常使用:
const b = [...new Set(a.map(d => d.id))].map(id => { const sameIdList = a.filter(d => d.id === id) const roleList = sameIdList.map(d => d.role) return { id: id, name: sameIdList[0].name, // 直接取同id第一条数据的name role: roleList.length === 1 ? roleList[0] : roleList } })
注:如果业务场景下同id对应的
name可能存在不同值,可以参考role的合并逻辑,把name也做数组收集处理,上述代码是基于示例中同id下name完全一致的前提编写。
内容的提问来源于stack exchange,提问作者palnic
相关产品推荐
相关产品推荐

