在java 8中按多个字段名称分组 [英] Group by multiple field names in 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 内部.此代码使用 record
但它可以很容易地成为 JEP 359 之前的 Java 版本中的类(定义了 equals
和 hashCode
)补充:
A second option is to define a class that represents the grouping. This can be inside Person. This code uses a record
but it could just as easily be a class (with equals
and hashCode
defined) in versions of Java before JEP 359 was added:
class Person {
record NameAge(String name, int age) { }
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 框架都有专为此类事情设计的 pair
类.例如:apache commons pair 如果您使用这些库中的一个,那么您可以将映射的键设为一对名称和年龄:
Finally if you don't want to implement your own group record then many of the Java frameworks around have a pair
class designed for 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));
我个人认为通用元组没有多大价值,因为记录在该语言中可用,因为记录可以更好地显示意图并且只需要很少的代码.
Personally I don't really see much value in generic tuples now that records are available in the language as records display intent better and require very little code.
这篇关于在java 8中按多个字段名称分组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!