Reputation: 3013
I have a list of users.
class User {
String name;
}
And I need to group users by name.
List<Set<User>> groupedBy;
The grouping condition is the name similarity, it's some Comparator
Comparator<User> p = new Comparator<User>() {
// some comparison logic
};
How can I group users by similar name using Java 8 streams?
I've tried to use partitioning
, but it has a different API than I need.
Map<Boolean, List<User>> collected = users.stream().collect(Collectors.partitioningBy(new Predicate<User>() {
@Override
public boolean test(User user) {
// ...
}
}, Collectors.toList()));
Upvotes: 1
Views: 6318
Reputation: 298123
Normally, if you want to group via a simple property, you’d use
Map<String,Set<User>> m=users.stream()
.collect(Collectors.groupingBy(User::getName, Collectors.toSet()));
however, if you have a complicated logic that is expressed as an already existing Comparator
, e.g.
Comparator<User> comparator=Comparator.comparing(u -> u.getName(), Collator.getInstance());
you can use
Map<User,Set<User>> m=users.stream().collect(
Collectors.groupingBy(u -> u, () -> new TreeMap<>(comparator), Collectors.toSet()));
to group according to the logic encapsulated in the comparator.
In both cases, you get a Map
which can be converted to your desired list using
List<Set<User>> groupedBy = new ArrayList<>(m.values());
You can also express the last step as part of the Collector
, e.g.
List<Set<User>> groupedBy=users.stream().collect(
Collectors.collectingAndThen(
Collectors.groupingBy(u -> u, () -> new TreeMap<>(comparator), Collectors.toSet()),
m -> new ArrayList<Set<User>>(m.values())));
Upvotes: 4