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

如何优雅地遍历Toggl API返回的数组并按用户名分组提取指定数据

如何优雅地遍历Toggl API返回的数组并按用户名分组提取指定数据

这是个很典型的分组合并需求,你想用伪代码实现的思路没问题,但其实用数组的reduce方法+映射表的方式会更优雅高效,代码也更简洁,我给你详细讲讲怎么实现:

首先先确认下你提供的原始Toggl API返回数据(我修正了语法错误,确保是合法的JSON数组):

[
  {
    "user_id": 12345,
    "username": "JohnSmith",
    "description": "foo",
    "time_entries": [
      {
        "id": 3778920070,
        "seconds": 10800,
        "start": "2025-01-27T11:00:00+00:00",
        "stop": "2025-01-27T14:00:00+00:00",
        "at": "2025-01-27T16:17:24+00:00",
        "at_tz": "2025-01-27T16:17:24+00:00"
      }
    ],
    "row_number": 1
  },
  {
    "user_id": 6789,
    "username": "JaneSmith",
    "description": "bar",
    "time_entries": [
      {
        "id": 3778684944,
        "seconds": 5977,
        "start": "2025-01-27T14:35:31+00:00",
        "stop": "2025-01-27T16:15:08+00:00",
        "at": "2025-01-27T16:15:09+00:00",
        "at_tz": "2025-01-27T16:15:09+00:00"
      }
    ],
    "row_number": 2
  },
  {
    "user_id": 12345,
    "username": "JohnSmith",
    "description": "bar",
    "time_entries": [
      {
        "id": 3780521038,
        "seconds": 3600,
        "start": "2025-01-27T09:00:00+00:00",
        "stop": "2025-01-27T10:00:00+00:00",
        "at": "2025-01-28T13:34:31+00:00",
        "at_tz": "2025-01-28T13:34:31+00:00"
      }
    ],
    "row_number": 3
  }
]

优雅的分组实现方案

我们可以用reduce方法来遍历数组,同时维护一个以用户名为键的临时对象(映射表),这样就能在O(n)的时间复杂度内完成分组(比嵌套循环的O(n²)高效太多,数据量大的时候差异特别明显):

// 假设原始数据是上面的togglData数组
const groupedData = Object.values(togglData.reduce((acc, currentItem) => {
  // 用用户名作为唯一标识键
  const usernameKey = currentItem.username;

  if (!acc[usernameKey]) {
    // 第一次遇到该用户:复制所有字段,直接存入映射表
    acc[usernameKey] = { ...currentItem };
  } else {
    // 用户已存在:合并time_entries数组
    acc[usernameKey].time_entries = [
      ...acc[usernameKey].time_entries,
      ...currentItem.time_entries
    ];
    // 额外说明:如果需要处理其他字段(比如description/row_number),可以在这里加逻辑
    // 例如要保留最后一次的description:acc[usernameKey].description = currentItem.description;
    // 或者合并成数组:acc[usernameKey].descriptions = [...(acc[usernameKey].descriptions || []), currentItem.description];
  }

  return acc;
}, {}));

// 输出结果
console.log(JSON.stringify(groupedData, null, 2));

代码逻辑解释

  1. reduce方法:它的核心是遍历数组并累积一个结果,这里我们用它来构建用户分组的映射表。
  2. 映射表acc:键是用户名,值是分组后的用户数据,这样查找用户是否存在的操作是O(1)的,非常高效。
  3. 扩展运算符...:用来浅拷贝对象和数组,避免修改原始数据,保证数据的纯净性。
  4. Object.values():最后把映射表的所有值提取出来,转换成你需要的数组格式。

最终输出效果

运行上面的代码后,你会得到按用户名分组、合并了time_entries的结果,和你期望的输出一致:

[
  {
    "user_id": 12345,
    "username": "JohnSmith",
    "description": "foo",
    "time_entries": [
      {
        "id": 3778920070,
        "seconds": 10800,
        "start": "2025-01-27T11:00:00+00:00",
        "stop": "2025-01-27T14:00:00+00:00",
        "at": "2025-01-27T16:17:24+00:00",
        "at_tz": "2025-01-27T16:17:24+00:00"
      },
      {
        "id": 3780521038,
        "seconds": 3600,
        "start": "2025-01-27T09:00:00+00:00",
        "stop": "2025-01-27T10:00:00+00:00",
        "at": "2025-01-28T13:34:31+00:00",
        "at_tz": "2025-01-28T13:34:31+00:00"
      }
    ],
    "row_number": 1
  },
  {
    "user_id": 6789,
    "username": "JaneSmith",
    "description": "bar",
    "time_entries": [
      {
        "id": 3778684944,
        "seconds": 5977,
        "start": "2025-01-27T14:35:31+00:00",
        "stop": "2025-01-27T16:15:08+00:00",
        "at": "2025-01-27T16:15:09+00:00",
        "at_tz": "2025-01-27T16:15:09+00:00"
      }
    ],
    "row_number": 2
  }
]

这种方式既简洁又高效,完全符合你想要的优雅需求,而且扩展性很强,后续如果需要处理其他字段的合并逻辑,只需要在else块里添加对应的代码即可。

备注:内容来源于stack exchange,提问作者Gary

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.14 15:33:05