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

如何用Lodash或原生JS按state和details正确实现多键分组?

解决按state和details的id集合多键分组的问题

问题描述

使用Lodash按state和details字段分组时出现错误:state为rejected但details中id不同的条目(docId 333333和444444)被归为同一组;同时state为accepted但details中id顺序不同的条目(docId 222222和1111111)未被正确合并。预期分组规则是:仅当state相同且details中的id集合完全一致(与顺序无关)时才归为一组。

预期分组结果:

[
  {
    "docId": "222222,1111111",
    "details": [
      {
        "id": 20656,
        "type": "Claimant",
        "name": "First Name Last Name"
      },
      {
        "id": 10000,
        "type": "Fellow",
        "name": "Fellow First Name Fellow Last Name"
      }
    ],
    "state": "accepted"
  },
  {
    "docId": "333333",
    "details": [
      {
        "id": 10000,
        "type": "Fellow",
        "name": "Fellow First Name Fellow Last Name"
      }
    ],
    "state": "rejected"
  },
  {
    "docId": "444444",
    "details": [
      {
        "id": 20656,
        "type": "Claimant",
        "name": "First Name Last Name"
      }
    ],
    "state": "rejected"
  }
]

错误原因

原代码中直接将details数组转为字符串作为分组键的一部分:${details},${state}。由于数组中的对象转字符串默认返回[object Object],导致所有单元素details的条目都会生成相同的键(如[object Object],rejected),从而被错误归组;同时,顺序不同的相同id集合会生成不同的数组字符串,导致本该合并的条目被分开。

解决方案

核心是生成唯一标识state和details id集合的分组键:

  1. 提取每个条目中details的所有id
  2. 对id数组进行排序(消除顺序影响)
  3. 将排序后的id数组转为字符串,与state拼接作为分组键

Lodash实现

const data = [
    {
      docId: 222222,
      state: "accepted",
      details: [
        { id: 20656, type: "Claimant", name: "First Name Last Name" },
        { id: 10000, type: "Fellow", name: "Fellow First Name Fellow Last Name" }
      ]
    },
    {
      docId: 1111111,
      state: "accepted",
      details: [
        { id: 10000, type: "Fellow", name: "Fellow First Name Fellow Last Name" },
        { id: 20656, type: "Claimant", name: "First Name Last Name" }
      ]
    },
    {
      docId: 333333,
      state: "rejected",
      details: [
        { id: 10000, type: "Fellow", name: "Fellow First Name Fellow Last Name" }
      ]
    },
    {
      docId: 444444,
      state: "rejected",
      details: [
        { id: 20656, type: "Claimant", name: "First Name Last Name" }
      ]
    }
  ];

const grouped = _(data)
  .groupBy(item => {
    // 生成唯一分组键:state + 排序后的id字符串
    const sortedIds = _.sortBy(item.details, 'id').map(d => d.id).join(',');
    return `${item.state}_${sortedIds}`;
  })
  .map((items) => ({
    docId: items.map(item => item.docId).join(','),
    details: items[0].details,
    state: items[0].state
  }))
  .value();

console.log(grouped);

原生JavaScript实现

const data = [
    {
      docId: 222222,
      state: "accepted",
      details: [
        { id: 20656, type: "Claimant", name: "First Name Last Name" },
        { id: 10000, type: "Fellow", name: "Fellow First Name Fellow Last Name" }
      ]
    },
    {
      docId: 1111111,
      state: "accepted",
      details: [
        { id: 10000, type: "Fellow", name: "Fellow First Name Fellow Last Name" },
        { id: 20656, type: "Claimant", name: "First Name Last Name" }
      ]
    },
    {
      docId: 333333,
      state: "rejected",
      details: [
        { id: 10000, type: "Fellow", name: "Fellow First Name Fellow Last Name" }
      ]
    },
    {
      docId: 444444,
      state: "rejected",
      details: [
        { id: 20656, type: "Claimant", name: "First Name Last Name" }
      ]
    }
  ];

// 分组逻辑
const groupedMap = data.reduce((acc, item) => {
  // 生成分组键
  const sortedIds = item.details
    .map(d => d.id)
    .sort((a, b) => a - b)
    .join(',');
  const key = `${item.state}_${sortedIds}`;
  
  if (!acc[key]) {
    acc[key] = [];
  }
  acc[key].push(item);
  return acc;
}, {});

// 转换为预期格式
const grouped = Object.values(groupedMap).map(items => ({
  docId: items.map(item => item.docId).join(','),
  details: items[0].details,
  state: items[0].state
}));

console.log(grouped);

说明

  • 排序id数组是为了消除details中id顺序不同的影响,确保相同id集合的条目生成相同的分组键
  • 两种实现均会输出符合预期的分组结果,后续可在此基础上添加排序逻辑

内容的提问来源于stack exchange,提问作者Whoopcg

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 21:10:45