Home > Software design >  How to find count of word in Java 8
How to find count of word in Java 8

Time:07-14

I'm having below sentence

Hello world Hello Stackoverflow

Expected output: (order is not concern)

{2=[Hello], 1=[world,Stackoverflow]}

Tried with below code:

        final String input = "Hello world Hello Stackoverflow";

        final Map<String, Long> output = Arrays.stream(input.split(" "))
            .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));

        System.out.println(output);

got below output:

{world=1, Hello=2, Stackoverflow=1}

I want to get Long as key and List<String> as value in Map

How to do this?

CodePudding user response:

You need to group the Map entries like this :

String input = "Hello world Hello Stackoverflow";

Map<Long, List<String>> output = Arrays.stream(input.split(" "))
    .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
    .entrySet() // Set<Entry<String, Long>>
    .stream() // Stream<Entry<String, Long>>
    .collect(Collectors.groupingBy(
      Map.Entry::getValue, 
      Collectors.mapping(Map.Entry::getKey, Collectors.toList())
    ));

System.out.println(output); // {1=[world, Stackoverflow], 2=[Hello]}

CodePudding user response:

Another approach using Collections.frequency and a Map<Long, Set<String>> to avoid having duplicates in the values:

final String input = "Hello world Hello Stackoverflow";
List<String> list  = Arrays.stream(input.split(" ")).collect(Collectors.toList());

final Map<Long, Set<String>> output = list.stream()
        .collect(Collectors.groupingBy(
                    str -> (long) Collections.frequency(list, str), Collectors.toSet()));

CodePudding user response:

is it possible to do in single stream?

Not really (or probably not as efficiently). You need to have the frequency of each word to use as a key. Continually updating the key during map construction is fraught with problems. And you would need to update the lists as well.

However, the following does the exact same thing but without a stream. So it is probably a little more efficient. And you can use your just created map as the source.

  • create a destination map.
  • iterate over the entrySet
  • computeIfAbsent will create the list if the key is not present.
  • it also returns the just created or existing value, a list in this case, so you can add the word.
Map<Long, List<String>> result = new HashMap<>();
for (Entry<String,Long> e : output.entrySet()) {
    result.computeIfAbsent(e.getValue(), v->new ArrayList<>())
            .add(e.getKey());
}

result.entrySet().forEach(System.out::println);

prints

1=[world, Stackoverflow]
2=[Hello]
  • Related