Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java Collectors grouping-by dynamic fields

I have the following nested groupingBy block:

Map<String,Map<String,Long>> namesCountersMap =
            events.stream().collect(
                Collectors.groupingBy(
                    namesDAO::getName,
                    Collectors.groupingBy(
                        genericDAO::SOME_DYNAMIC_FIELD,
                        Collectors.counting())
                )
            );

There is a situation where I need to call this block 3 times, and the only thing I change is the inner groupingBy field ("SOME_DYNAMIC_FIELD").

Basically what i'm trying to do, is to use group-by and counting for a different field (at the second level) every time, and then merge the results.

Example:

{
      "NamesRecords": {
        "Sam": {
            "Cars": 4
            "Bags": 6 
            "Houses": 2 
        },

        "Bob": {
            "Cars": 2
            "Bags": 1 
            "Houses": 3 
        },

      }
}

As you can see, group-by at the 2nd level is done by 3 different fields, that's is why I need to duplicate this block of code three times.

If I pass a parameter of fieldToGroupBy to the function, is there a way I can use it dynamically? Or if you have any other ideas of how to avoid code duplication, I would love to hear.

like image 957
אברגיל יעקובו Avatar asked Jun 20 '26 01:06

אברגיל יעקובו


1 Answers

The first argument to Collectors.groupingBy is a Function<T,R>, so you can use a variable of that type.

It is simply a functional interface with a method for extracting the value to group by, and it can be implemented by a method reference, a lambda expression, an anonymous class, or any other type of class.

Function<namesDAO, String> classifier2 = genericDAO::SOME_DYNAMIC_FIELD;

Map<String,Map<String,Long>> namesCountersMap =
        events.stream().collect(
            Collectors.groupingBy(
                namesDAO::getName,
                Collectors.groupingBy(
                    classifier2,
                    Collectors.counting())
            )
        );

Now you can assign different values to classifier2, e.g.

Function<namesDAO, String> classifier2 = someDAO::getCars;

Function<namesDAO, String> classifier2 = otherDAO::getBags;

Function<namesDAO, String> classifier2 = dao -> dao.getHouses();
like image 145
Andreas Avatar answered Jun 22 '26 15:06

Andreas