在java 8中按多个字段名分组 [英] Group by multiple field names in java 8

查看:1502
本文介绍了在java 8中按多个字段名分组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我找到了通过POJO的某个字段名称对对象进行分组的代码。下面是代码:

I found the code for grouping the objects by some field name from POJO. Below is the code for that:

public class Temp {

    static class Person {

        private String name;
        private int age;
        private long salary;

        Person(String name, int age, long salary) {

            this.name = name;
            this.age = age;
            this.salary = salary;
        }

        @Override
        public String toString() {
            return String.format("Person{name='%s', age=%d, salary=%d}", name, age, salary);
        }
    }

    public static void main(String[] args) {
        Stream<Person> people = Stream.of(new Person("Paul", 24, 20000),
                new Person("Mark", 30, 30000),
                new Person("Will", 28, 28000),
                new Person("William", 28, 28000));
        Map<Integer, List<Person>> peopleByAge;
        peopleByAge = people
                .collect(Collectors.groupingBy(p -> p.age, Collectors.mapping((Person p) -> p, toList())));
        System.out.println(peopleByAge);
    }
}

输出是(这是正确的):

And the output is (which is correct):

{24=[Person{name='Paul', age=24, salary=20000}], 28=[Person{name='Will', age=28, salary=28000}, Person{name='William', age=28, salary=28000}], 30=[Person{name='Mark', age=30, salary=30000}]}

但如果我想按多个字段分组怎么办?显然,在那个POJO中实现 equals()方法之后,我可以在 groupingBy()方法中传递一些POJO但是有没有其他选项,比如我可以通过给定POJO中的多个字段进行分组?

But what if I want to group by multiple fields? I can obviously pass some POJO in groupingBy() method after implementing equals() method in that POJO but is there any other option like I can group by more than one fields from the given POJO?

例如在我的情况下,我想按姓名和年龄分组。

E.g. here in my case, I want to group by name and age.

推荐答案

这里有几个选项。最简单的是链接你的收藏家:

You have a few options here. The simplest is to chain your collectors:

Map<String, Map<Integer, List<Person>>> map = people
    .collect(Collectors.groupingBy(Person::getName,
        Collectors.groupingBy(Person::getAge));

然后,要获得一份名为Fred的18岁人员名单,您将使用:

Then to get a list of 18 year old people called Fred you would use:

map.get("Fred").get(18);

第二个选项是定义一个表示分组的类。这可以在Person中:

A second option is to define a class that represents the grouping. This can be inside Person:

class Person {
    public static class NameAge {
        public NameAge(String name, int age) {
            ...
        }

        // must implement equals and hash function
    }

    public NameAge getNameAge() {
        return new NameAge(name, age);
    }
}

然后你可以使用:

Map<NameAge, List<Person>> map = people.collect(Collectors.groupingBy(Person::getNameAge));

和用

map.get(new NameAge("Fred", 18));

最后,如果你不想实现自己的组类,那么许多Java框架都有一个类,专为此类事物而设计。例如: apache commons pair 如果你使用这些库中的一个,然后你可以为地图的关键字创建一对名称和年龄:

Finally if you don't want to implement your own group class then many of the Java frameworks around have a pair class designed for exactly this type of thing. For example: apache commons pair If you use one of these libraries then you can make the key to the map a pair of the name and age:

Map<Pair<String, Integer>, List<Person>> map =
    people.collect(Collectors.groupingBy(p -> Pair.of(p.getName(), p.getAge())));

并检索:

map.get(Pair.of("Fred", 18));

就我个人而言,我真的不喜欢这些元组库。它们似乎与良好的OO设计完全相反:它们隐藏意图而不是暴露它。

Personally I really dislike these tuple libraries. They seem to be the exact opposite of good OO design: they hide intent instead of exposing it.

说过你可以通过定义自己的分组来组合后两个选项类,但通过扩展 Pair 来实现它 - 这为您节省了很多定义等于等所涉及的工作并隐藏使用元组只是一个方便的实现细节,就像任何其他集合一样。

Having said that you can combine the second two options by defining your own grouping class but implementing it by just extending Pair - that saves you a lot of the work involved in defining equals etc and hides the use of the tuple as just a convenient implementation detail like any other collection.

祝你好运。

这篇关于在java 8中按多个字段名分组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆