JavaScript 常用数据处理函数 groupBy

一、前言

数据处理与分析中,对数据进行分组是非常常见的功能,不论是实际工作中,还是在面试的场景中应用十分广泛。尤其在函数式编程中 groupBy 十分常见。在 JavaScript 中 groupBy 也已经进入了 JS 的标准。

二、介绍

groupBy 函数是一个用于对 数组元素 进行 分组 的实用函数。groupBy 允许我们指定分组条件,将数组的元素分为不同的组,用于数据处理或者展示。

三、标准

proposal-array-grouping : tc39.es/proposal-ar...

  • Object.groupBy
ts 复制代码
Object.groupBy(items, callbackFn) // 语法,第一个参数是可迭代对象,第二参数是回调函数
  • Map.groupBy
ts 复制代码
Map.groupBy(items, callbackFn) // 语法,第一个参数是可迭代对象,第二参数是回调函数

四、环境支持

五、Object.groupBy 示例

ts 复制代码
const data = [
  { id: 1, type: 'A' },
  { id: 2, type: 'B' },
  { id: 3, type: 'A' },
  { id: 4, type: 'C' },
  { id: 5, type: 'B' },
];
const groupType = Object.groupBy(data, 'type') // ❌ 第二个参数必须是函数
const groupType = Object.groupBy(data, (item) => item.type) // ✅ 按照类型进行分类, 并且 type 就是 group 的 key 值。
// {
//   A: [{...}, {...}]
//   B: [{...}, {...}]
//   C: [{...}]
/ }

六、实现一个按照给 key 据分组

虽然函数通用性更加广泛,但是复杂度比直接传递数据要稍微高一点,这里实现一个按照传递属性方式实现一个 groupBy:

ts 复制代码
function groupBy(arr, key) {
  return arr.reduce((acc, obj) => {
    const groupKey = obj[key];
    acc[groupKey] = acc[groupKey] || [];
    acc[groupKey].push(obj);
    return acc;
  }, {});
}

// data 复用以上的 data
groupBy(data, 'type') // 输出结果与 Object.groupBy 一致

实现的核心思想就是 reduce 进行 累加。从 {} 对象开始,然后再对象上赋值对应key为空数组,符合这个key 的就进入此分组。

七、实现一个通用的 groupBy

有了基于 key 实现 groupBy 之后,实现通用的 groupBy 就比较容易了:

ts 复制代码
type KeyFunc<T> = (obj: T) => string

export function groupByWithFn<T>(
  array: T[],
  keyFunc: KeyFunc<T>
): Record<string, T[]> {
  return array.reduce((acc: Record<string, T[]>, obj: T) => {
    const key: string = keyFunc(obj)
    if (!acc[key]) {
      acc[key] = []
    }
    acc[key].push(obj)
    return acc
  }, {})
}

这里用 TS 实现主要约束类型,本质也非常简单就是 keyFunc 用当前的 obj 执行获取 key,如果没有获取到了,设置一个空的数组初始化,并将数据填充进去。重复累积这个过程。

八、lodash z中的 groupBy

ts 复制代码
_.groupBy(data, (item) => item.type)

lodash 将 groupBy 放在 collection 集合中,而非数组中。实用方式与以上基本一致。

九、rxjs groupBy

如果是函数式编程,当然离不开 RxJS 中数据操作。rxjs groupBy 不能单独的实现 js 中 groupBy 的功能,当然我们组合操作符或者自定义操作符实现。以下是实现一个自定义操作符 customGroupBy

ts 复制代码
import { Observable, of } from 'rxjs';
import { map, mergeMap, reduce } from 'rxjs/operators';

// 自定义 groupBy 操作符
function customGroupBy(keySelector) {
  return function (source) {
    return new Observable((observer) => {
      source.pipe(
        mergeMap((arr) => arr),
        reduce((acc, val) => {
          const key = keySelector(val);
          acc[key] = acc[key] || [];
          acc[key].push(val);
          return acc;
        }, {})
      ).subscribe({
        next: (result) => {
          observer.next(result);
          observer.complete();
        },
        error: (err) => observer.error(err),
      });
    });
  };
}

of([
    { id: 1, type: 'A' },
    { id: 2, type: 'B' },
    { id: 3, type: 'A' },
    { id: 4, type: 'C' },
    { id: 5, type: 'B' },
  ]).pipe(
  customGroupBy((obj) => obj.type)
).subscribe({
  next: (v) => {console.log(v)}
});

customGroupBy 操作符,接受一个函数作为参数,当然这个函数式是一个闭包,包含了 of 操作符中的静态数据。customGroupBy 是典型的自定义操作符实现,source 的就是 of 制作的静态可观察对象。后面的逻辑也是实用 reduce 进行累加计算。然后对外输出数据

十、groupBy 其他

  • 在 SQL 中,GROUP BY 语句用于将行分组为汇总行。
  • 在 Python 中,可以使用 itertools.groupby 对可迭代对象进行分组。
  • 在一些数据处理例如 excel 以及 python 的工具库中。

十一、小结

本文主要介绍 JavaScript 中的 groupBy 函数实用特性。从 ES 标准草案,到自己实现一个简单的 groupBy, 再到 lodash 以及 RxJS 中实现 groupBy 效果。在函数式编程中,groupBy 实用特性非常高,在数据处理领域广泛适用。

相关推荐
小研说技术6 分钟前
实时通信对比,一场MCP协议的技术革命
前端·后端·面试
kyriewen10 分钟前
React Hooks原理:为什么不能写在if里?揭开Hook的“魔法”面纱
前端·react.js·前端框架
ServBay10 分钟前
2026年 Go 开发中没有它就不行的 10 个库
后端·go
敲代码的彭于晏13 分钟前
Claude Code Token 烧得太快?这8个方案帮你立省90%!
前端·ai编程·claude
可视之道14 分钟前
设备拓扑图中的实时状态映射与动画策略:告警闪烁、流向动画、质量码怎么共存
前端
涂兵兵_青石疏影16 分钟前
绘制图像-clip方法
前端
之歆31 分钟前
Day03_HTML 列表、表格、表单完整指南(下)
android·javascript·html
焦糖玛奇朵婷33 分钟前
解锁扭蛋机小程序的五大优势
java·大数据·服务器·前端·小程序
SwJieJie44 分钟前
windsurf的配置和项目规则、工作流、agent技巧使用
前端
SamDeepThinking1 小时前
别让一个超时的第三方http接口拖垮所有接口
java·后端·架构