I want to group a list of person's. A person have some attributes like name, country, town, zipcode, etc. I wrote the static code, which works very well:
Object groupedData = data.stream().collect(groupingBy(Person::getName, Collectors.groupingBy(Person::getCountry, Collectors.groupingBy(Person::getTown))));
But the problem is, that is it not dynamic. Sometimes I want to just group by name and town, sometimes by a attributes. How can I do this? Non Java 8 solutions are welcome as well.
You could create a function taking an arbitrary number of attributes to group by and construct the groupingBy
-Collector
in a loop, each time passing the previous version of itself as the downstream
collector.
public static <T> Map collectMany(List<T> data, Function<T, ?>... groupers) {
Iterator<Function<T, ?>> iter = Arrays.asList(groupers).iterator();
Collector collector = Collectors.groupingBy(iter.next());
while (iter.hasNext()) {
collector = Collectors.groupingBy(iter.next(), collector);
}
return (Map) data.stream().collect(collector);
}
Note that the order of the grouper
functions is reversed, so you have to pass them in reversed order (or reverse them inside the function, e.g. using Collections.reverse
or Guava's Lists.reverse
, whichever you prefer).
Object groupedData = collectMany(data, Person::getTown, Person::getCountry, Person::getName);
Or like this, using an old-school for
loop to reverse the array in the function, i.e. you don't have to pass the groupers in inverse order (but IMHO this is harder to comprehend):
public static <T> Map collectMany(List<T> data, Function<T, ?>... groupers) {
Collector collector = Collectors.groupingBy(groupers[groupers.length-1]);
for (int i = groupers.length - 2; i >= 0; i--) {
collector = Collectors.groupingBy(groupers[i], collector);
}
return (Map) data.stream().collect(collector);
}
Both approaches will return a Map<?,Map<?,Map<?,T>>>
, just as in your original code. Depending on what you want to do with that data it might also be worth considering using a Map<List<?>,T>
, as suggested by Tunaki.
Collected from the Internet
Please contact [email protected] to delete if infringement.
Comments