Group by multiple field names in java 8
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));
Then to get a list of 18 year old people called Fred you would use:
map.get("Fred").get(18);
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);
}
}
Then you can use:
Map<NameAge, List<Person>> map = people.collect(Collectors.groupingBy(Person::getNameAge));
and search with
map.get(new NameAge("Fred", 18));
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())));
and retrieve with:
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.
Here look at the code:
You can simply create a Function and let it do the work for you, kind of functional Style!
Function<Person, List<Object>> compositeKey = personRecord ->
Arrays.<Object>asList(personRecord.getName(), personRecord.getAge());
Now you can use it as a map:
Map<Object, List<Person>> map =
people.collect(Collectors.groupingBy(compositeKey, Collectors.toList()));
Cheers!
Hi You can simply concatenate your groupingByKey
such as
Map<String, List<Person>> peopleBySomeKey = people
.collect(Collectors.groupingBy(p -> getGroupingByKey(p), Collectors.mapping((Person p) -> p, toList())));
//write getGroupingByKey() function
private String getGroupingByKey(Person p){
return p.getAge()+"-"+p.getName();
}