Reputation: 7141
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 Owner
s?
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...
Upvotes: 3
Views: 17172
Reputation: 34460
If you know that
one
ContactNumber
can 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
ContactNumber
could 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
.
Upvotes: 8
Reputation: 7141
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)
);
Upvotes: 5