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

相关推荐
大家的林语冰33 分钟前
CSS 已死?DOM 性能黑洞!Pretext 排版革命让你在文本间跳舞,没有 DOM 也能纵享丝滑~
前端·javascript·css
vipbic43 分钟前
我也该升级了,陪伴了我7年的博客
前端
程序猿追1 小时前
我搭了个网页工具:输入关键词,SERP API 自动吐出比价 Excel
后端
Lee川1 小时前
RAG 实战:从一篇掘金文章出发,拆解检索增强生成的全链路
前端·人工智能·后端
Lee川1 小时前
MCP 高德地图实战:当 AI 学会使用工具,一个协议如何重塑大模型的行动边界
前端·人工智能·后端
楼田莉子1 小时前
C++17新特性:__had_include/属性/求值顺序规则
开发语言·c++·后端
ZC跨境爬虫1 小时前
跟着 MDN 学CSS day_14:(尺寸调整技能测试与实战解析)
前端·css·ui·html·tensorflow
kyriewen2 小时前
用魔法打败魔法:我让AI替我去面试前端岗,AI面试官给我打了92分,还发了offer
前端·javascript·面试
程序员cxuan2 小时前
Codex 把我家烂网给优化后,我 TM 直接原地起飞了。
人工智能·后端·程序员
IT_陈寒2 小时前
Redis批量删除踩了坑,原来DEL命令不是万能的
前端·人工智能·后端