Given the following list as example :
List<String> input = List.of("FOO", "FOO", "FOO", "FOO", "FOO", "BAR", "BAR", "BAZ", "BAZ", "BAZ", "DOO", "DOO");
I need to get the relative Frequency of each element and print it formatted as a string. To do so I have used 2 steps, first create a frequency map and then calculate relative percentage and format:
Map<String, Long> relativeFrequency =
input.stream().collect(Collectors.groupingBy(Function.identity(),Collectors.counting()));
Map<String, String> relativeFrequency2 = relativeFrequency.entrySet().stream()
.collect(Collectors.toMap(Map.Entry::getKey,
entry -> String.format ( "%.02f%%", entry.getValue() * 100. / input.size() )));
System.out.println(relativeFrequency2);
and get the result
{BAR=16.67%, DOO=16.67%, FOO=41.67%, BAZ=25.00%}
I was told to refactor the above and do it in one go using Collectors.collectingAndThen, but I can't seem to find the right syntax (compile error Operator '*' cannot be applied to '<lambda parameter>', 'double'
). Can someone help to correct the following to get the same result as above?
Map<String, String> relativeFrequency3 =
input.stream().collect(Collectors.collectingAndThen(Collectors.groupingBy(Function.identity(), Collectors.counting(),
total -> String.format ( "%.02f%%", total * 100. / input.size() ))
));
CodePudding user response:
You were close.
List<String> input =
List.of("FOO", "FOO", "FOO", "FOO", "FOO", "BAR",
"BAR", "BAZ", "BAZ", "BAZ", "DOO", "DOO");
- the first argument to
collectingAndThen
would becounting()
to get the frequency. - then you process that frequency by converting it to a formatted percentage.
Map<String, String> map = input.stream().collect(Collectors
.groupingBy(a -> a, Collectors.collectingAndThen(
Collectors.counting(),
count -> "%.2f%%".formatted((double) count
/ input.size() * 100))));
map.entrySet().forEach(System.out::println);
printing each entry set yields
BAR=16.67%
DOO=16.67%
FOO=41.67%
BAZ=25.00%
CodePudding user response:
import java.util.*;
import java.util.stream.*;
import java.util.function.Function;
class Main {
public static void main(String args[]) {
var input = List.of("FOO", "FOO", "FOO", "FOO", "FOO", "BAR", "BAR", "BAZ", "BAZ", "BAZ", "DOO", "DOO");
var out = input.stream()
.collect(Collectors.groupingBy(w -> w, Collectors.collectingAndThen(Collectors.summingInt(w -> 1), s -> String.format ("%.02f%%", s * 100. / input.size() ))));
System.out.println(out);
}
}
{BAR=16.67%, DOO=16.67%, FOO=41.67%, BAZ=25.00%}