JavaScript如何实现数组按属性分组

 更新时间:2023年08月29日 11:30:47   作者:一花一world  
在JavaScript中,有多种方法可以对数组按属性进行分组,这篇文章主要为大家至少介绍了6种常见的方法,感兴趣的小伙伴可以跟随小编一起学习一下

在JavaScript中,有多种方法可以对数组按属性进行分组。以下是至少6种常见的方法:

6种方法的使用场景和优缺点的简要描述

1.使用reduce()方法

使用场景:适用于需要对数组进行聚合操作的情况,可以自定义聚合逻辑。

优点:灵活性高,可以自定义聚合逻辑;可以同时对多个属性进行分组。

缺点:代码相对复杂,需要熟悉reduce()方法的使用。

2.使用forEach()方法:

使用场景:适用于简单的分组需求,不需要自定义聚合逻辑。

优点:简单易懂,代码量较少。

缺点:无法同时对多个属性进行分组;不支持链式操作。

3.使用map()方法和Object.create(null):

使用场景:适用于需要创建一个纯净的空对象作为分组结果的情况。

优点:可以创建一个没有原型链的空对象,避免可能的属性冲突。

缺点:相对于使用普通对象,性能稍差。

4.使用Map对象:

使用场景:适用于需要对分组结果进行进一步操作的情况,如遍历、删除、更新等。

优点:支持对分组结果进行灵活的操作;可以同时对多个属性进行分组。

缺点:相对于普通对象,Map对象的性能稍差。

5.使用lodash库的groupBy()方法:

使用场景:适用于使用lodash库的项目,或者需要使用其他lodash库的功能。

优点:简单易用,代码量少;lodash库提供了丰富的其他功能。

缺点:引入了额外的库,增加了项目的依赖。

6.使用ES6的Map和箭头函数:

使用场景:适用于需要使用ES6的特性,或者需要对分组结果进行进一步操作的情况。

优点:支持对分组结果进行灵活的操作;可以同时对多个属性进行分组;使用了ES6的特性。

缺点:相对于普通对象,Map对象的性能稍差。

根据具体的需求和项目环境,选择适合的方法可以提高代码的可读性和性能。对于简单的分组需求,可以选择forEach()方法或lodash库的groupBy()方法;对于复杂的分组需求,可以选择reduce()方法、Map对象或ES6的Map和箭头函数。

1.使用reduce()方法封装的方法

这种方法使用reduce()方法来对数组进行迭代,并根据指定的属性值将元素分组。它使用一个空对象作为初始值,然后在迭代过程中,根据属性值将元素添加到相应的分组中。

  • 首先创建一个空对象,用于存储分组结果。
  • 使用for循环遍历数组中的每个元素。
  • 在每次迭代中,使用if语句检查当前元素的属性值是否已经存在于分组对象中。
  • 如果属性值不存在,就创建一个新的属性,并将当前元素添加到该属性对应的数组中。
  • 如果属性值已经存在,就将当前元素添加到该属性对应的数组中。
  • 最后返回分组对象。

使用示例:

const arr = [
  { name: 'Alice', age: 20, gender: 'female' },
  { name: 'Bob', age: 25, gender: 'male' },
  { name: 'Charlie', age: 20, gender: 'male' },
  { name: 'David', age: 30, gender: 'male' },
  { name: 'Eve', age: 25, gender: 'female' }
];
const result = groupByReduce(arr, 'age');
console.log(result);

输出结果:

{
  '20': [
    { name: 'Alice', age: 20, gender: 'female' },
    { name: 'Charlie', age: 20, gender: 'male' }
  ],
  '25': [
    { name: 'Bob', age: 25, gender: 'male' },
    { name: 'Eve', age: 25, gender: 'female' }
  ],
  '30': [
    { name: 'David', age: 30, gender: 'male' }
  ]
}

2.使用forEach()方法封装的方法

这种方法使用forEach()方法对数组进行迭代,并根据指定的属性值将元素分组。它使用一个空对象作为初始值,然后在迭代过程中,根据属性值将元素添加到相应的分组中。

  • 使用reduce方法对数组进行迭代,并传入一个初始值为空对象。
  • 在每次迭代中,使用初始值作为累加器,并根据当前元素的属性值,将元素添加到相应的属性数组中。
  • 最后返回累加器,即分组结果。

使用示例:

const arr = [
  { name: 'Alice', age: 20, gender: 'female' },
  { name: 'Bob', age: 25, gender: 'male' },
  { name: 'Charlie', age: 20, gender: 'male' },
  { name: 'David', age: 30, gender: 'male' },
  { name: 'Eve', age: 25, gender: 'female' }
];
const result = groupByForEach(arr, 'gender');
console.log(result);

输出结果:

{
  female: [
    { name: 'Alice', age: 20, gender: 'female' },
    { name: 'Eve', age: 25, gender: 'female' }
  ],
  male: [
    { name: 'Bob', age: 25, gender: 'male' },
    { name: 'Charlie', age: 20, gender: 'male' },
    { name: 'David', age: 30, gender: 'male' }
  ]
}

3.使用map()方法和Object.create(null)封装的方法

这种方法使用map()方法对数组进行迭代,并根据指定的属性值将元素分组。它使用Object.create(null)创建一个没有原型的空对象作为初始值,然后在迭代过程中,根据属性值将元素添加到相应的分组中。

  • 创建一个空的Map对象,用于存储分组结果。
  • 使用forEach方法对数组进行迭代。
  • 在每次迭代中,根据当前元素的属性值,使用Map对象的get方法获取对应的属性数组。
  • 如果属性数组不存在,就创建一个新的属性数组,并将当前元素添加到该数组中。
  • 如果属性数组已经存在,就将当前元素添加到该数组中。
  • 最后将分组结果转换为普通对象,并返回。

使用示例:

const arr = [
  { name: 'Alice', age: 20, gender: 'female' },
  { name: 'Bob', age: 25, gender: 'male' },
  { name: 'Charlie', age: 20, gender: 'male' },
  { name: 'David', age: 30, gender: 'male' },
  { name: 'Eve', age: 25, gender: 'female' }
];
const result = groupByMap(arr, 'age');
console.log(result);

输出结果:

{
  '20': [
    { name: 'Alice', age: 20, gender: 'female' },
    { name: 'Charlie', age: 20, gender: 'male' }
  ],
  '25': [
    { name: 'Bob', age: 25, gender: 'male' },
    { name: 'Eve', age: 25, gender: 'female' }
  ],
  '30': [
    { name: 'David', age: 30, gender: 'male' }
  ]
}

4.使用Map对象封装的方法

这种方法使用Map对象来存储分组结果。它使用forEach()方法对数组进行迭代,并根据指定的属性值将元素分组。在迭代过程中,根据属性值将元素添加到相应的分组中,并使用Map对象的set()方法来保存分组结果。

  • 创建一个空的Map对象,用于存储分组结果。
  • 使用forEach方法对数组进行迭代。
  • 在每次迭代中,使用箭头函数来根据当前元素的属性值,将元素添加到相应的属性数组中。
  • 最后将分组结果转换为普通对象,并返回。

使用示例:

const arr = [
  { name: 'Alice', age: 20, gender: 'female' },
  { name: 'Bob', age: 25, gender: 'male' },
  { name: 'Charlie', age: 20, gender: 'male' },
  { name: 'David', age: 30, gender: 'male' },
  { name: 'Eve', age: 25, gender: 'female' }
];
const result = groupByMapObj(arr, 'gender');
console.log(result);

输出结果:

{
  female: [
    { name: 'Alice', age: 20, gender: 'female' },
    { name: 'Eve', age: 25, gender: 'female' }
  ],
  male: [
    { name: 'Bob', age: 25, gender: 'male' },
    { name: 'Charlie', age: 20, gender: 'male' },
    { name: 'David', age: 30, gender: 'male' }
  ]
}

5.使用lodash库的groupBy()方法封装的方法

这种方法使用lodash库的groupBy()方法来实现分组。它接受一个数组和一个属性名作为参数,并返回一个对象,其中键是属性值,值是具有相同属性值的元素数组。

  • 使用lodash库的groupBy方法,传入数组和属性名作为参数。
  • groupBy方法会根据属性值将数组元素分组,并返回一个对象,其中键是属性值,值是具有相同属性值的元素数组。
  • 返回分组结果

使用示例:

const arr = [
  { name: 'Alice', age: 20, gender: 'female' },
  { name: 'Bob', age: 25, gender: 'male' },
  { name: 'Charlie', age: 20, gender: 'male' },
  { name: 'David', age: 30, gender: 'male' },
  { name: 'Eve', age: 25, gender: 'female' }
];
const result = groupByLodash(arr, 'age');
console.log(result);

输出结果:

{
  '20': [
    { name: 'Alice', age: 20, gender: 'female' },
    { name: 'Charlie', age: 20, gender: 'male' }
  ],
  '25': [
    { name: 'Bob', age: 25, gender: 'male' },
    { name: 'Eve', age: 25, gender: 'female' }
  ],
  '30': [
    { name: 'David', age: 30, gender: 'male' }
  ]
}

6.使用ES6的Map和箭头函数封装的方法

这种方法使用ES6的Map对象来存储分组结果。它使用forEach()方法对数组进行迭代,并根据指定的属性值将元素分组。在迭代过程中,根据属性值将元素添加到相应的分组中,并使用Map对象的set()方法来保存分组结果。

  • 创建一个空的Map对象,用于存储分组结果。
  • 使用forEach方法对数组进行迭代。
  • 在每次迭代中,使用箭头函数来根据当前元素的属性值,将元素添加到相应的属性数组中。
  • 最后将分组结果转换为普通对象,并返回。

使用示例:

const arr = [
  { name: 'Alice', age: 20, gender: 'female' },
  { name: 'Bob', age: 25, gender: 'male' },
  { name: 'Charlie', age: 20, gender: 'male' },
  { name: 'David', age: 30, gender: 'male' },
  { name: 'Eve', age: 25, gender: 'female' }
];
const result = groupByMapArrow(arr, 'gender');
console.log(result);

输出结果:

{
  female: [
    { name: 'Alice', age: 20, gender: 'female' },
    { name: 'Eve', age: 25, gender: 'female' }
  ],
  male: [
    { name: 'Bob', age: 25, gender: 'male' },
    { name: 'Charlie', age: 20, gender: 'male' },
    { name: 'David', age: 30, gender: 'male' }
  ]
}

以上是六种不同的方法的详细说明和使用示例。根据需求和个人喜好,可以选择适合的方法来进行分组操作。

7.试着封装起来

以下是将这6种方法封装

function groupBy(arr, prop, method) {
  switch (method) {
    case 'reduce':
      return arr.reduce((result, item) => {
        const key = item[prop];
        if (!result[key]) {
          result[key] = [];
        }
        result[key].push(item);
        return result;
      }, {});
    case 'forEach':
      const grouped = {};
      arr.forEach(item => {
        const key = item[prop];
        if (!grouped[key]) {
          grouped[key] = [];
        }
        grouped[key].push(item);
      });
      return grouped;
    case 'map':
      const grouped = Object.create(null);
      arr.map(item => {
        const key = item[prop];
        if (!grouped[key]) {
          grouped[key] = [];
        }
        grouped[key].push(item);
      });
      return grouped;
    case 'mapObj':
      const grouped = new Map();
      arr.forEach(item => {
        const key = item[prop];
        const group = grouped.get(key) || [];
        group.push(item);
        grouped.set(key, group);
      });
      return Object.fromEntries(grouped);
    case 'lodash':
      const _ = require('lodash');
      return _.groupBy(arr, prop);
    case 'mapArrow':
      const grouped = new Map();
      arr.forEach(item => {
        const key = item[prop];
        const group = grouped.get(key) || [];
        group.push(item);
        grouped.set(key, group);
      });
      return Object.fromEntries(grouped);
    default:
      return {};
  }
}

使用示例:

const arr = [
  { name: 'Alice', age: 20, gender: 'female' },
  { name: 'Bob', age: 25, gender: 'male' },
  { name: 'Charlie', age: 20, gender: 'male' },
  { name: 'David', age: 30, gender: 'male' },
  { name: 'Eve', age: 25, gender: 'female' }
];
​​​​​​​console.log(groupBy(arr, 'age', 'reduce'));
console.log(groupBy(arr, 'gender', 'forEach'));
console.log(groupBy(arr, 'age', 'map'));
console.log(groupBy(arr, 'gender', 'mapObj'));
console.log(groupBy(arr, 'age', 'lodash'));
console.log(groupBy(arr, 'gender', 'mapArrow'));

封装后,可以根据传入的方法名调用相应的分组方法,方便调用和切换不同的分组方法。

到此这篇关于JavaScript如何实现数组按属性分组的文章就介绍到这了,更多相关JavaScript数组分组内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • layui对工具条进行选择性的显示方法

    layui对工具条进行选择性的显示方法

    今天小编就为大家分享一篇layui对工具条进行选择性的显示方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-09-09
  • js实现页面打印功能实例代码(附去页眉页脚功能代码)

    js实现页面打印功能实例代码(附去页眉页脚功能代码)

    js实现页面打印功能实例代码(附去页眉页脚功能代码)
    2009-12-12
  • JavaScript绘制游戏地图并且操控人物移动

    JavaScript绘制游戏地图并且操控人物移动

    JavaScript开发小游戏,目标是使用JavaScript绘制简单的二维地图,采用二维数组存储地图信息,使用表格绘制地图,每个td单元格存储数据,使用JavaScript keyPress键盘事件监听WASD键,按键触发时人物做出相应操作,人物下一步碰撞到障碍物,终止人物运动
    2023-10-10
  • json_decode 索引为数字时自动排序问题解决方法

    json_decode 索引为数字时自动排序问题解决方法

    这篇文章主要介绍了使用son_encode 给前端返回数据,结果顺序不对,经debug调试,发现是json_encode 函数的问题,变成 " " + 数字即可,需要的朋友可以参考下
    2020-03-03
  • View.post() 不靠谱的地方你知道多少

    View.post() 不靠谱的地方你知道多少

    本文给大家分享了view.post()方法不靠谱的地方,以及post在7.0中的差异,需要的的朋友参考下本文吧
    2017-08-08
  • 浅谈webpack下的AOP式无侵入注入

    浅谈webpack下的AOP式无侵入注入

    下面小编就为大家带来一篇浅谈webpack下的AOP式无侵入注入。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-11-11
  • ES6解构赋值实例详解

    ES6解构赋值实例详解

    这篇文章主要介绍了ES6解构赋值,结合实例形式较为详细的分析了ES6结构赋值的基本概念、原理与使用方法,需要的朋友可以参考下
    2017-10-10
  • 基于事件冒泡、事件捕获和事件委托详解

    基于事件冒泡、事件捕获和事件委托详解

    这篇文章主要介绍了事件冒泡、事件捕获和事件委托,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-07-07
  • JS代码计算LocalStorage容量示例详解

    JS代码计算LocalStorage容量示例详解

    这篇文章主要为大家介绍了JS代码计算LocalStorage容量的示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-07-07
  • JS利用ffmpeg和sharp玩转音视频和图片

    JS利用ffmpeg和sharp玩转音视频和图片

    ffmpeg 是一个非常流行的开源软件套件,用于处理音频和视频数据,而要想对图片之类的进行压缩,我们可以选择 sharp 来进行操作,所以下面我们就来学习一下前端如何利用ffmpeg和sharp玩转音视频和图片吧
    2023-10-10

最新评论