JavaScript 中的数组分组(2024)

2025-06-10

JavaScript 中的数组分组(2024)

数组分组是您可能在 JavaScript 中实现过的任务。如果您使用 SQL,它类似于执行GROUP BY。给定一个数据集,我们可以通过将相似的数据放入一个组中,并使用给定的标识符标识每个组来组成更高级别的数据集。

我将深入研究今年(2024 年)发布的新数组分组Object.groupBy函数,即和Map.groupBy

对于我的 TypeScript 粉丝来说, TypeScript 5.4版本已经支持这些 API 。不过,你需要将你的tsconfig.json目标配置为ESNext。当它们在 ES2024 中可用时,你可以将目标设置为ES2024或更高版本。

2024 年之前的阵列分组

JavaScript 中的数组分组并非新概念,我们已经在各种方法中实现了它。它可以通过underscore.jslodashfor中的或foreach循环Array.prototype.reduce、或groupBy函数来实现

给定一个员工列表,我们将使用以下方式对数据进行分组reduce()

interface Employee {
  name: string;
  department: string;
  age: number;
  manager?: Employee;
  joined: Date
}

const ceo = {
    name: "John Doe",
    department: "engineering",
    age: 47,
    joined: new Date("10-04-2020")
}

const cfo = {
    name: "Anna Maria",
    department: "finance",
    age: 45,
    joined: new Date("10-05-2020")
  }

 const employees: Employee[] = [
  ceo,
  {
    name: "Pop Jones Jr.",
    department: "finance",
    age: 30,
    manager: cfo,
    joined: new Date("10-04-2021")
  },
  {
    name: "Sarah Clara",
    department: "engineering",
    age: 32,
    manager: ceo,
    joined: new Date("10-05-2021")
  },
  cfo,
  {
    name: "Funmi Kola",
    department: "engineering",
    age: 20,
    manager: ceo,
    joined: new Date("10-05-2022")
  },
  {
    name: "Julius Maria",
    department: "sales",
    age: 27,
    manager: cfo,
    joined: new Date("10-05-2022")
  }
 ]

const groupByDepartment = employees.reduce<Record<string, Employee[]>>((acc, employee) => {
  const department = employee.department;
  if (acc[department] === undefined) {
    acc[department] = [];
  }

  acc[department].push(employee);
  return acc;
}, {});

console.log(groupByDepartment);
Enter fullscreen mode Exit fullscreen mode

的输出groupByDepartment应该是:

{
    "engineering": [
        {
            "name": "John Doe",
            "department": "engineering",
            "age": 47,
            "joined": "2020-10-03T22:00:00.000Z"
        },
        {
            "name": "Sarah Clara",
            "department": "engineering",
            "age": 32,
            "manager": {
                "name": "John Doe",
                "department": "engineering",
                "age": 47,
                "joined": "2020-10-03T22:00:00.000Z"
            },
            "joined": "2021-10-04T22:00:00.000Z"
        },
        {
            "name": "Funmi Kola",
            "department": "engineering",
            "age": 20,
            "manager": {
                "name": "John Doe",
                "department": "engineering",
                "age": 47,
                "joined": "2020-10-03T22:00:00.000Z"
            },
            "joined": "2022-10-04T22:00:00.000Z"
        }
    ],
    "finance": [
        {
            "name": "Pop Jones Jr.",
            "department": "finance",
            "age": 30,
            "manager": {
                "name": "Anna Maria",
                "department": "finance",
                "age": 45,
                "joined": "2020-10-04T22:00:00.000Z"
            },
            "joined": "2021-10-03T22:00:00.000Z"
        },
        {
            "name": "Anna Maria",
            "department": "finance",
            "age": 45,
            "joined": "2020-10-04T22:00:00.000Z"
        }
    ],
    "sales": [
        {
            "name": "Julius Maria",
            "department": "sales",
            "age": 27,
            "manager": {
                "name": "Anna Maria",
                "department": "finance",
                "age": 45,
                "joined": "2020-10-04T22:00:00.000Z"
            },
            "joined": "2022-10-04T22:00:00.000Z"
        }
    ]
}
Enter fullscreen mode Exit fullscreen mode

使用 Object.groupBy 进行分组

Object.groupBy函数用于按给定的字符串值进行分组。这意味着:给定一个可迭代对象,根据其提供的回调函数返回的值对其元素进行分组。回调函数的返回值必须是可以强制转换为字符串或符号的值。

Object.groupBy返回一个空原型对象,该对象为每个组提供单独的属性,其中包含包含该组元素的数组。使用空原型对象可以实现符合人体工程学的解构,并防止与全局 Object 属性发生意外冲突。

使用相同的数据集,我们可以根据员工的部门对其进行分组Object.groupBy

const groupByDepartment = Object.groupBy(employees, ({department}) => department)
Enter fullscreen mode Exit fullscreen mode

这给出了与方法相同的结果,reduce但代码更少。 的输出groupByDepartment应该是:

{
    "engineering": [
        {
            "name": "John Doe",
            "department": "engineering",
            "age": 47,
            "joined": "2020-10-03T22:00:00.000Z"
        },
        {
            "name": "Sarah Clara",
            "department": "engineering",
            "age": 32,
            "manager": {
                "name": "John Doe",
                "department": "engineering",
                "age": 47,
                "joined": "2020-10-03T22:00:00.000Z"
            },
            "joined": "2021-10-04T22:00:00.000Z"
        },
        {
            "name": "Funmi Kola",
            "department": "engineering",
            "age": 20,
            "manager": {
                "name": "John Doe",
                "department": "engineering",
                "age": 47,
                "joined": "2020-10-03T22:00:00.000Z"
            },
            "joined": "2022-10-04T22:00:00.000Z"
        }
    ],
    "finance": [
        {
            "name": "Pop Jones Jr.",
            "department": "finance",
            "age": 30,
            "manager": {
                "name": "Anna Maria",
                "department": "finance",
                "age": 45,
                "joined": "2020-10-04T22:00:00.000Z"
            },
            "joined": "2021-10-03T22:00:00.000Z"
        },
        {
            "name": "Anna Maria",
            "department": "finance",
            "age": 45,
            "joined": "2020-10-04T22:00:00.000Z"
        }
    ],
    "sales": [
        {
            "name": "Julius Maria",
            "department": "sales",
            "age": 27,
            "manager": {
                "name": "Anna Maria",
                "department": "finance",
                "age": 45,
                "joined": "2020-10-04T22:00:00.000Z"
            },
            "joined": "2022-10-04T22:00:00.000Z"
        }
    ]
}
Enter fullscreen mode Exit fullscreen mode

使用 Map.groupBy 进行分组

Map.groupBy与 类似Object.groupBy,不同之处在于它返回一个 Map,并且可以使用任意值对给定的可迭代对象进行分组。在本例中,可以使用对象对数据集进行分组。

回顾数据集,我们manager为一些员工定义了一个属性,并为其分配了ceocfo对象。我们可以根据员工的 对其进行分组manager,如下所示:

const managerWithTeammates = Map.groupBy(employees, ({manager}) => manager)
Enter fullscreen mode Exit fullscreen mode

的输出managerWithTeammates应类似于:

Map (3) 
{undefined => [{
  "name": "John Doe",
  "department": "engineering",
  "age": 47,
  "joined": "2020-10-03T22:00:00.000Z"
}, {
  "name": "Anna Maria",
  "department": "finance",
  "age": 45,
  "joined": "2020-10-04T22:00:00.000Z"
}], 
{
  "name": "Anna Maria",
  "department": "finance",
  "age": 45,
  "joined": "2020-10-04T22:00:00.000Z"
} => [{
  "name": "Pop Jones Jr.",
  "department": "finance",
  "age": 30,
  "manager": {
    "name": "Anna Maria",
    "department": "finance",
    "age": 45,
    "joined": "2020-10-04T22:00:00.000Z"
  },
  "joined": "2021-10-03T22:00:00.000Z"
}, {
  "name": "Julius Maria",
  "department": "sales",
  "age": 27,
  "manager": {
    "name": "Anna Maria",
    "department": "finance",
    "age": 45,
    "joined": "2020-10-04T22:00:00.000Z"
  },
  "joined": "2022-10-04T22:00:00.000Z"
}], 
{
  "name": "John Doe",
  "department": "engineering",
  "age": 47,
  "joined": "2020-10-03T22:00:00.000Z"
} => [{
  "name": "Sarah Clara",
  "department": "engineering",
  "age": 32,
  "manager": {
    "name": "John Doe",
    "department": "engineering",
    "age": 47,
    "joined": "2020-10-03T22:00:00.000Z"
  },
  "joined": "2021-10-04T22:00:00.000Z"
}, {
  "name": "Funmi Kola",
  "department": "engineering",
  "age": 20,
  "manager": {
    "name": "John Doe",
    "department": "engineering",
    "age": 47,
    "joined": "2020-10-03T22:00:00.000Z"
  },
  "joined": "2022-10-04T22:00:00.000Z"
}]}
Enter fullscreen mode Exit fullscreen mode

在这个例子中,我们有 3 个组:

  1. 没有经理的CEO和CFO,以undefined作为Map对象键。

  2. 首席财务官 Anna Maria 手下有两名员工。这使用cfo对象作为 Map 对象的键。

  3. 首席执行官 John Doe 手下有两名员工。这将使用该ceo对象作为 Map 对象的键。

结论

JavaScript 即将推出的新 API 是不是令人惊叹?Object.groupByandMap.groupBy函数让数组或可迭代对象中的数据分组变得更容易,而且比传统方法更符合人体工程学。此外,它们不需要像or 这样的reduce外部库,从而减少了包的大小lodashunderscore.js

总结一下,该Map.groupBy函数主要用于对与任意对象关联的元素进行分组,尤其是当该对象可能随时间变化时。如果对象是不变的,您可以改用字符串表示,并使用 对元素进行分组Object.groupBy()。如果使用 TypeScript,请将目标设置为ESNext(或 ,ES2024当它在未来可用时)。

如果您有任何问题或建议,请随时发表评论。您也可以通过Twitter联系我。感谢您的阅读😎

您将通过此链接找到一个包含此博客文章中使用的代码的游乐场

如果您对类似主题但视频格式感兴趣,请订阅我的YouTube 频道www.youtube.com/@pmbanugo

最初由我撰写并发布在Telerik 的博客上

鏂囩珷鏉ユ簮锛�https://dev.to/pmbanugo/array-grouping-in-javascript-2024-5cm9
PREV
寻找最佳 React 表单库?它可能就在这个列表中
NEXT
Pop!_OS 有什么大不了的?