You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 20:42:17