1

I am trying to group the following list of Foo objects by getName() and count occurrences while ordering by getNumber() in ascending order.

Input:

List<Foo> fooList = List.of(
    new Foo("Alpha", 1.1f),
    new Foo("Delta", 1.2f),
    new Foo("Charlie", 3.1f),
    new Foo("Alpha", 2.1f),
    new Foo("Charlie", 4.1f),
    new Foo("Delta", 2.2f)
);

Map Output:

{Alpha=2, Delta=2, Charlie=2}

My current solution is as follows:

Map<String, Integer> map = new LinkedHashMap<>();

fooList
    .stream()
    .sorted(Comparator.comparingDouble(Foo::getNumber))
    .forEach(foo -> {
        int val = map.getOrDefault(foo.getName(), 0);
        map.put(foo.getName(), val + 1); 
    });

Is there any better way with Collectors.groupingBy()?

Alexander Ivanchenko
  • 25,667
  • 5
  • 22
  • 46
A_X
  • 89
  • 1
  • 6

1 Answers1

2

Is there any better way with Collectors.groupingBy()?

You need the flavor of groupingBy(classifier,mapFactory,downstream) which allows to specify a mapFactory.

As a downstream collector, we need to apply combination of collectingAndThen() and counting() because the resulting type produced by counting() is Long and we need to turn it into Integer.

Map<String, Integer> fooNameByCount = fooList.stream()
    .sorted(Comparator.comparing(Foo::getNumber))
    .collect(Collectors.groupingBy(
        Foo::getName,
        LinkedHashMap::new,
        Collectors.collectingAndThen(Collectors.counting(),
            Long::intValue)
    ));

We can achieve the same result by using a single collector with the following version of toMap(keyMapper,valueMapper,mergeFunction,mapFactory):

Map<String, Integer> fooNameByCount = fooList.stream()
    .sorted(Comparator.comparing(Foo::getNumber))
    .collect(Collectors.toMap(
        Foo::getName,
        foo -> 1,
        Integer::sum,
        LinkedHashMap::new
    ));

Also note that using collector is always a preferred way to accumulate the result.

Usage of forEach() such cases when you generate the result by the means of collect(), reduce(), etc. is discouraged by the API documentation

Alexander Ivanchenko
  • 25,667
  • 5
  • 22
  • 46