对按matchday值分组对象数组的Array reduce实现逻辑的疑问
基于matchday分组的reduce实现逻辑拆解
整体实现思路
这段代码的最终目标是把散在数组里的比赛数据,按matchday值聚合成嵌套数组,整个流程拆为两个独立步骤:
- 通过
Array.reduce迭代原数组,把同matchday的比赛归到同一个数组下,生成一个键为matchday值、值为对应比赛集合的普通对象 - 通过
Object.values提取上述对象里的所有属性值,去掉作为临时标识的matchday键,最终生成两层结构的嵌套数组
逐行拆解reduce核心逻辑
先回顾reduce的通用结构:原数组.reduce(迭代回调, 迭代初始值),这段代码里设置的迭代初始值是{}(空对象),这个对象就是整个迭代过程的“累加器”,会在每次循环中保留之前累计的分组状态。
迭代回调每次执行时会接收两个参数:
acc:也就是上面说的累加器对象,存储到当前位置为止已经分好组的所有数据m:原数组中当前正在遍历的单条比赛数据
回调内的三行代码逻辑依次是:
acc[m.matchday] = acc[m.matchday] || [];
这行是分组的核心判断:如果累加器中已经存在以当前比赛的matchday为标识的分组(即已经建过对应数组),就保留原有的分组数组;如果还没有建过对应分组,就初始化一个空数组,避免后续插入数据时报错。acc[m.matchday].push(m);
不管是刚初始化的空数组,还是已经存了多条同组比赛的旧数组,都把当前遍历到的比赛数据,插入到对应matchday分组的数组末尾。return acc;
把更新完分组状态的累加器返回,作为下一次循环的初始值,保证之前累计的分组数据不会丢失。
实际迭代的状态变化参考
我们可以跟着循环的实际流程看状态变化,对逻辑的理解会更直观:
- 第一次循环拿到matchday为1的第一条比赛时,累加器是空对象,没有
1对应的分组,因此给acc[1]赋值空数组,把当前比赛push进去,此时累加器结构为{ 1: [第一条比赛] } - 后续两条matchday为1的比赛进入循环时,累加器里已经存在
1对应的分组数组,因此直接把比赛push进去,直到matchday为1的三条比赛全部存入acc[1] - 第一次拿到matchday为2的比赛时,累加器里没有
2对应的分组,因此新建空数组存入acc[2],后续两条matchday为2的比赛同样直接push到这个分组数组里
等所有数组遍历完成,reduce最终返回的对象结构为{ 1: [3条matchday=1的比赛], 2: [3条matchday=2的比赛] }
外层Object.values的作用
我们最终需要的是纯嵌套数组,不需要之前作为分组标识的matchday键。Object.values()会遍历传入对象的所有可枚举属性,把所有属性值(也就是我们分好组的比赛数组)按顺序收集成新的数组返回,最终就得到了控制台打印的两层嵌套结构。
小提示:作为对象键的matchday值(数字类型)会被JS隐式转换为字符串类型,但因为我们最后只提取值不使用键,所以这个隐式转换不会影响最终结果。
内容的提问来源于stack exchange,提问作者Noud
相关产品推荐
相关产品推荐

