javadictionaryjava-streamcollectors

How to perform arithmetic on the result of Collectors.counting()?


Given:

List<Integer> myIntegers = Arrays.asList(1, 1, 2, 3, 4, 2);

Return:

an Integer = Sum(((Frequency of Integer) / 2)))

I'm able to get the frequency of each integer using Collectors.groupingBy(), but want to then divide each frequency value by 2 and then sum all the values in the map, returning just an Integer:

Map<Integer, Long> myIntegerMap = myIntegers.stream().collect(Collectors.groupingby(Function.identity(), Collectors.counting()));

for(Map.Entry<Integer, Long> a : myIntegerMap.entrySet()){ System.out.print(a.getKey(), + "==>"); System.out.println(a.getValue());}

Output:

1 ==> 2

2 ==> 2

3 ==> 1

4 ==> 1

Desired Output:

( ( 2 / 2 ) + ( 2 / 2 ) + ( 1 / 2 ) + ( 1 / 2 ) ) = 2


Solution

  • You don't need to use two statements. You can do it in the same construct as doing the frequency count.

    First compute the frequencies and then use CollectingAndThen to post process the map and add up the values after dividing by 2 to get the desired result.

    long result = myIntegers.stream().collect(Collectors.collectingAndThen(
             Collectors.groupingBy(Function.identity(),
                     Collectors.counting()),
               mp -> mp.values().stream().mapToLong(a->a/2).sum()))
    
    System.out.println(result);
    

    prints

    2