How to Group a List of Objects by Field in Java
Suppose we have a Dog
class in Java with breed
and name
attributes.
class Dog {
int id;
String breed;
Dog(int id, String breed) {
this.id = id;
this.breed = breed;
}
int getId() { return this.id; }
String getBreed() { return this.breed; }
}
And let’s suppose we have a list of Dog
objects.
List<Dog> lst = new ArrayList<Dog>();
lst.add(new Dog(1, "corgi"));
lst.add(new Dog(2, "shih tzu"));
lst.add(new Dog(3, "corgi"));
lst.add(new Dog(4, "corgi"));
lst.add(new Dog(5, "husky"));
lst.add(new Dog(6, "shih tzu"));
How can we group these Dog
objects by the breed
field?
Using a for
loop
We can do this quite easily using a simple for loop and conditional.
Map<String, List<Dog>> grouped = new HashMap<String, List<Dog>>();
for (Dog dog : lst) {
String key = dog.breed;
if (!grouped.containsKey(key)) {
grouped.put(key, new ArrayList<Dog>());
}
grouped.get(key).add(student);
}
Using the Stream API’s groupingBy()
In Java 8, we can use stream()
and collect()
to achieve the same functionality.
Map<String, List<Dog>> grouped =
lst.stream().collect(Collectors.groupingBy(o -> o.breed));
We can generalize this function using this same Collectors.groupingBy()
method.
public static <E, K> Map<K, List<E>> groupBy(List<E> list, Function<E, K> keyFunction) {
return Optional.ofNullable(list)
.orElseGet(ArrayList::new)
.stream()
.collect(Collectors.groupingBy(keyFunction));
}
Map<String, List<Dog>> grouped = groupBy(lst, Dog::getBreed);