Count frequency(Specialized) in Java 8 using Lambdas

I have a list of strings like this: "na","na","na","uk","uk". I want to count the frequency of each element in such a way that if the existing map’s value is even, then I will add 1; otherwise 2.

 List<String> streamer=Arrays.asList("na","na","na","uk","uk");
        Map<String,Integer> m=new HashMap<>();
        for(String s:streamer)
        {
            if(m.containsKey(s))
            {
                if(m.get(s)%2==0)
                    m.put(s,m.get(s)+1);
                else
                    m.put(s,m.get(s)+2);
            }
            else
                m.put(s,1);
        }
        System.out.println("CUSTOM Frequency::::"+m); 

Now, I want to achieve the exact same thing using streams and lambdas. All I could do is this:

Map<String, Long>map4 = streamer.stream()
                .collect(Collectors.groupingBy(Function.identity(),
                        Collectors.counting())); //How can I get custom counting instead of Collectors.counting()?

>Solution :

Besides @Sweeper’s answer to get the expected counting result, if your question also implied how to customize a collect operation, you could use the method of() of the Collector class.

https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/stream/Collector.html#of(java.util.function.Supplier,java.util.function.BiConsumer,java.util.function.BinaryOperator,java.util.stream.Collector.Characteristics…)

The method accepts a supplier, an accumulator as a BiConsumer and a combiner as a BinaryOperator. The supplier simply provides the container where to store the result, in your case a Map<String, Long>. The accumulator populates the container by putting or updating an entry with the custom frequency logic. Lastly, The combiner simply merges the sub-results of parallel executions in case the stream is executed as a parallel stream.

List<String> streamer = Arrays.asList("na", "na", "na", "uk", "uk");
Map<String, Long> map4 = streamer.stream()
        .collect(Collector.of(
                HashMap::new,
                (Map<String, Long> map, String s) -> {
                    if (!map.containsKey(s)) {
                        map.put(s, 1L);
                    } else {
                        map.computeIfPresent(s, (String key, Long val) -> val % 2 != 0 ? val + 2 : val + 1);
                    }
                },
                (Map<String, Long> map1, Map<String, Long> map2) -> {
                    map1.putAll(map2);
                    return map1;
                }
        ));

Output

{na=5, uk=3}

Leave a Reply