I have a list of cars
List<Car> cars = ...;
A car has an Owner and and Owner has a ContactNumber
Car
public class Car {
private Owner owner;
public Owner getOwner(){
return owner;
}
}
Owner
public class Owner {
private ContactNumber contactNumber;
public ContactNumber getContactNumber() {
return contactNumber;
}
}
I know I can group cars by Owners using
Map<Owner, List<Car>> groupByOwner = cars.stream().collect(groupingBy(Car::getOwner));
Is there a way I can then use streams to group by Owner and ContactNumber knowing that one ContactNumber can only ever be associated with one Owner?
How would I also do this if a ContactNumber could be shared by multiple Owners?
i.e to create the below map:
Map<Owner, List<Car>> groupByOwner = cars.stream().collect(groupingBy(Car::getOwner))
Map<ContactNumber, Map<Owner, List<Car>>> groupByContactNumberAndOwner = groupByOwner...
If you know that
one
ContactNumbercan only ever be associated with oneOwner
Then, you don't need inner maps. Just group directly by ContactNumber:
Map<ContactNumber, List<Car>> groupByOwnerContactNumber = cars.stream()
.collect(Collectors.groupingBy(c -> c.getOwner().getContactNumber()));
Don't be afraid to use lambda expressions ;)
EDIT:
As per the second part of your question:
if a
ContactNumbercould be shared by multipleOwners
You could do a nested grouping by using the overloaded version of Collectors.groupingBy that accepts a downstream collector:
Map<ContactNumber, Map<Owner, List<Car>>> groupByOwnerAndContactNumber =
cars.stream().collect(Collectors.groupingBy(
c -> c.getOwner().getContactNumber(),
Collectors.groupingBy(Car::getOwner)));
Another way would be to group by a compound key (ContactNumber, Owner). You can achieve this by letting the key be a List<Object>:
Map<List<Object>, List<Car>> groupByCompundOwnerContactNumber =
cars.stream().collect(Collectors.groupingBy(
c -> Arrays.asList(c.getOwner().getContactNumber(), c.getOwner())));
This doesn't require a nested grouping operation.
Note: if you're using Java 9 you can use List.of instead of Arrays.asList.
To get the Map<ContactNumber, Map<Owner, List<Car>>> collection I was looking for I had to do:
Map<ContactNumber, Map<Owner, List<Car>>> response = cars.stream()
.collect(groupingBy(c -> c.getOwner().getContactNumber(), groupingBy(Car::getOwner)));
Using the overloaded collector
groupingBy(Function<? super T, ? extends K> classifier, Collector<? super T, A, D> downstream)
Where you would use:
groupingBy(
list element -> root key of the map,
groupingBy(list element -> second level key of the map)
);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With