我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Java stream多字段分组(groupingBy)

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Java stream多字段分组(groupingBy)

近期的项目里,遇到一个需求:对于含有多个元素的List,按照其中的某几个属性进行分组,比如Persion::getAgePersion::getTypePersion::getGender等字段。下面就让我们讨论一下如何比较优雅的按多字段进行分组groupingBy。

利用Stream进行分组

Stream是Java8的一个新特性,主要用户集合数据的处理,如排序、过滤、去重等等功能,这里我们不展开讲解。本文主要讲解的是利用Stream.collect()来对List进行分组。
Person类Person.java:

public class Person {        private Integer id;        private Integer age;        private String type;        private String name;        private String gender;    public Integer getId() {        return id;    }    public Person setId(Integer id) {        this.id = id;        return this;    }    public Integer getAge() {        return age;    }    public Person setAge(Integer age) {        this.age = age;        return this;    }    public String getType() {        return type;    }    public Person setType(String type) {        this.type = type;        return this;    }    public String getName() {        return name;    }    public Person setName(String name) {        this.name = name;        return this;    }    public String getGender() {        return gender;    }    public Person setGender(String gender) {        this.gender = gender;        return this;    }}

1. 利用单个字段进行分组

如上面的Person类,如果对于其中的某一个字段进行分组(如gender),则比较简单,我们可以利用Stream.collect()Collectors.groupingBy结合,即可进行分组groupingBy,代码如下:

public class TestGroupingBy {    public static void main(String[] args) {        List<Person> personList = Arrays.asList(                new Person().setId(1).setAge(18).setType("student").setName("user - 1").setGender("male"),                new Person().setId(2).setAge(20).setType("student").setName("user - 2").setGender("male"),                new Person().setId(3).setAge(18).setType("student").setName("user - 3").setGender("male"),                new Person().setId(4).setAge(18).setType("student").setName("user - 4").setGender("male"),                new Person().setId(5).setAge(35).setType("teacher").setName("user - 5").setGender("male"),                new Person().setId(6).setAge(35).setType("teacher").setName("user - 6").setGender("male"),                new Person().setId(7).setAge(20).setType("student").setName("user - 7").setGender("male"),                new Person().setId(8).setAge(20).setType("student").setName("user - 8").setGender("female"),                new Person().setId(9).setAge(20).setType("student").setName("user - 9").setGender("female"),                new Person().setId(10).setAge(20).setType("student").setName("user - 10").setGender("female")        );        Map<String, List<Person>> groupingMap = personList.stream().collect(Collectors.groupingBy(Person::getGender));}

其中的groupingMap ,类型为Map>,第一个泛型为String即分组字段(本例中为gender字段)的类型,第二个泛型为List及分组结果的类型。
我们在Debug模式下运行代码,可以看到groupingMap 数据如下:
单个字段分组结果
可以看到personList数据按照gender属性被分成了两组。

2. 利用多个字段进行分组

上面的例子是按单个字段分组,如果需要按照多个字段,如gender、age、type三个字段进行分组,同样也可以可以利用Stream.collect()Collectors.groupingBy结合的方式进行分组,不过该方式中调用Collectors.groupingBy时需要多次嵌套调用,测试代码如下:

public class TestGroupingBy {    public static void main(String[] args) {        List<Person> personList = Arrays.asList(                new Person().setId(1).setAge(18).setType("student").setName("user - 1").setGender("male"),                new Person().setId(2).setAge(20).setType("student").setName("user - 2").setGender("male"),                new Person().setId(3).setAge(18).setType("student").setName("user - 3").setGender("male"),                new Person().setId(4).setAge(18).setType("student").setName("user - 4").setGender("male"),                new Person().setId(5).setAge(35).setType("teacher").setName("user - 5").setGender("male"),                new Person().setId(6).setAge(35).setType("teacher").setName("user - 6").setGender("male"),                new Person().setId(7).setAge(20).setType("student").setName("user - 7").setGender("male"),                new Person().setId(8).setAge(20).setType("student").setName("user - 8").setGender("female"),                new Person().setId(9).setAge(20).setType("student").setName("user - 9").setGender("female"),                new Person().setId(10).setAge(20).setType("student").setName("user - 10").setGender("female")        );        // 多字段嵌套分组        Map<String, Map<Integer, Map<String, List<Person>>>> groupingMap = personList.stream().collect(                Collectors.groupingBy(Person::getGender,                         Collectors.groupingBy(Person::getAge,     Collectors.groupingBy(Person::getType)                        )                )        );    }}

其中groupingMap类型为Map>>>,是一个嵌套了三层的Map,对应的泛型String/Integer/String分别为对应分组字段的类型,最后一层Map的value类型为List为实际分组后的数据集合类型,为方便查看数据,特意按Json格式贴出数据如下:

{  "female": {    "20": {      "student": [        {          "id": 8,          "age": 20,          "type": "student",          "name": "user - 8",          "gender": "female"        },        {          "id": 9,          "age": 20,          "type": "student",          "name": "user - 9",          "gender": "female"        },        {          "id": 10,          "age": 20,          "type": "student",          "name": "user - 10",          "gender": "female"        }      ]    }  },  "male": {    "18": {      "student": [        {          "id": 1,          "age": 18,          "type": "student",          "name": "user - 1",          "gender": "male"        },        {          "id": 3,          "age": 18,          "type": "student",          "name": "user - 3",          "gender": "male"        },        {          "id": 4,          "age": 18,          "type": "student",          "name": "user - 4",          "gender": "male"        }      ]    },    "20": {      "student": [        {          "id": 2,          "age": 20,          "type": "student",          "name": "user - 2",          "gender": "male"        },        {          "id": 7,          "age": 20,          "type": "student",          "name": "user - 7",          "gender": "male"        }      ]    },    "35": {      "teacher": [        {          "id": 5,          "age": 35,          "type": "teacher",          "name": "user - 5",          "gender": "male"        },        {          "id": 6,          "age": 35,          "type": "teacher",          "name": "user - 6",          "gender": "male"        }      ]    }  }}

可以看到,原先的List数据,按照gender/age/type三个属性,分成了三层的Map,对于这种多层的Map代码上处理起来会有一些不方便。并且如果分组字段更多的话,所嵌套的Collectors.groupingBy也会更加多,代码书写起来也不太优雅。

下面将介绍另外一种按多字段分组的方法。

3. 利用Collectors.groupingBy与Function结合进行多字段分组

查看Collectors.groupingByAPI会发现,其中一种用法是第一个参数为Function,如下:
在这里插入图片描述
简单翻译一下就是:一种将输入元素映射到键的分类函数。即需要定义一个函数Function,该函数将元素对象映射到一个键的集合里。代码示例如下:

public class TestGroupingBy {    public static void main(String[] args) {        List<Person> personList = Arrays.asList(                new Person().setId(1).setAge(18).setType("student").setName("user - 1").setGender("male"),                new Person().setId(2).setAge(20).setType("student").setName("user - 2").setGender("male"),                new Person().setId(3).setAge(18).setType("student").setName("user - 3").setGender("male"),                new Person().setId(4).setAge(18).setType("student").setName("user - 4").setGender("male"),                new Person().setId(5).setAge(35).setType("teacher").setName("user - 5").setGender("male"),                new Person().setId(6).setAge(35).setType("teacher").setName("user - 6").setGender("male"),                new Person().setId(7).setAge(20).setType("student").setName("user - 7").setGender("male"),                new Person().setId(8).setAge(20).setType("student").setName("user - 8").setGender("female"),                new Person().setId(9).setAge(20).setType("student").setName("user - 9").setGender("female"),                new Person().setId(10).setAge(20).setType("student").setName("user - 10").setGender("female")        );        // 定义一个函数Function,该函数将元素对象映射到一个键的集合里        Function<Person, List<Object>> compositeKey = person ->                Arrays.asList(person.getGender(), person.getAge(), person.getType());        // 分组        Map<List<Object>, List<Person>> groupingMap =                personList.stream().collect(Collectors.groupingBy(compositeKey, Collectors.toList()));    }}

通过在Debug模式下运行代码,可以看到groupingMap的数据结构如下:
在这里插入图片描述
groupingMap数据仅仅只有一层,但是其键值Key却是一个List,里面包含了分组字段的值,如上图中的male35teacher是集合中属性gender/age/type分别是male35teacher的元素集合。数据按Json格式贴出如下:

{  "[male, 35, teacher]": [    {      "id": 5,      "age": 35,      "type": "teacher",      "name": "user - 5",      "gender": "male"    },    {      "id": 6,      "age": 35,      "type": "teacher",      "name": "user - 6",      "gender": "male"    }  ],  "[female, 20, student]": [    {      "id": 8,      "age": 20,      "type": "student",      "name": "user - 8",      "gender": "female"    },    {      "id": 9,      "age": 20,      "type": "student",      "name": "user - 9",      "gender": "female"    },    {      "id": 10,      "age": 20,      "type": "student",      "name": "user - 10",      "gender": "female"    }  ],  "[male, 20, student]": [    {      "id": 2,      "age": 20,      "type": "student",      "name": "user - 2",      "gender": "male"    },    {      "id": 7,      "age": 20,      "type": "student",      "name": "user - 7",      "gender": "male"    }  ],  "[male, 18, student]": [    {      "id": 1,      "age": 18,      "type": "student",      "name": "user - 1",      "gender": "male"    },    {      "id": 3,      "age": 18,      "type": "student",      "name": "user - 3",      "gender": "male"    },    {      "id": 4,      "age": 18,      "type": "student",      "name": "user - 4",      "gender": "male"    }  ]}

由于Map只有一层,用该方式分组的结果,对于我们业务也是比较友好,代码里对数据处理起来也是比较方便的。可以看到,从代码书写角度以及分组处理后得到的结果,该方法都是最优雅的。

写在最后

可以看到,如果分组字段只有一个,我们可以用比较简单的利用Stream.collect()Collectors.groupingBy进行处理,但对于多个字段的分组操作,建议还是用Collectors.groupingByFunction进行处理。

来源地址:https://blog.csdn.net/m0_58016522/article/details/131082125

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Java stream多字段分组(groupingBy)

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Java stream多字段分组(groupingBy)

近期的项目里,遇到一个需求:对于含有多个元素的List,按照其中的某几个属性进行分组,比如Persion::getAge、Persion::getType、Persion::getGender等字段。下面就让我们讨论一下如何比较优雅的按
2023-08-21

Java8 Stream之groupingBy分组使用解读

这篇文章主要介绍了Java8 Stream之groupingBy分组使用,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
2023-05-17

Java stream sorted怎么使用Comparator进行多字段排序

这篇文章主要介绍了Java stream sorted怎么使用Comparator进行多字段排序的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Java stream sorted怎么使用Comparator进行
2023-07-05

Java stream sorted使用 Comparator 进行多字段排序的方法

这篇文章主要介绍了Java stream sorted使用 Comparator 进行多字段排序,主要讲解使用Java Stream流排序器Comparator对List集合进行多字段排序的方法,包括复杂实体对象多字段升降序排序方法,需要的朋友可以参考下
2023-03-06

PHP 数组按多个字段分组的方法详解

如何按多个字段分组 php 数组?array_column():按指定字段分组,提取该字段的值作为键。array_multisort():按多个字段排序数组,对相邻的重复行分组。自定义函数:定义自定义函数,使用循环按指定字段分组数组。PHP
PHP 数组按多个字段分组的方法详解
2024-05-04

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录