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 实用特性非常高,在数据处理领域广泛适用。

相关推荐
前端之虎陈随易8 小时前
编程语言级别的Skill市场,AI Agent 的未来形态
前端·vue.js·人工智能·typescript·node.js
一路向北he8 小时前
字节钢铁军团--“提供情境,而非控制”
java·开发语言·前端
码事漫谈8 小时前
别写Prompt了,现在流行给AI“写循环”
后端
kyriewen8 小时前
豆包和千问同时关了智能体,我用它们搭的 3 个自动化全废了——迁移方案整理
前端·javascript·ai编程
前端一小卒8 小时前
我用 TypeScript 从零手写了一个 Claude Code,然后发现它的核心只有 30 行
前端·agent
铁皮饭盒9 小时前
用 Bun.cron 定时 7 月 7 日,为啥? 看图1
javascript
Kyrie_Li9 小时前
Spring Boot Kafka 生产级配置全解析:从入门到精通
spring boot·后端·kafka
Coder_Shenshen9 小时前
西门子S7CommPlus协议鉴权算法原理与流程详解
网络·后端·算法
大圣编程10 小时前
Python中continue语句的用法是什么?
开发语言·前端·python
yuhaiqiang10 小时前
随手 vibecoding 的浏览器插件已经 6000 多次下载,聊聊他的产品设计
前端·后端·面试