I am working on an exercise to count words in a phrase.
I have a regex I'm happy with to split the phrase into word tokens, so I can complete the work with basic loops - no problem.
But I'd like to use streams to collect the strings into a map instead of using basic loops.
I need each word as a key and, for now, I'd just like the integer 1
as the value.
Having done some research online I should be able to collect the list of words into a map like so:
public Map<String, Integer> phrase(String phrase) {
List<String> words = //... tokenized words from phrase
return words.stream().collect(Collectors.toMap(word -> word, 1));
}
I have tried this, and several variations (casting word
, using Function.identity()
), but keep getting the error:
The method toMap(Function<? super T,? extends K>, Function<? super T,? extends U>) in the type Collectors is not applicable for the arguments ((<no type> s) -> {}, int)
Any example I've found to date only uses the string as the value, but otherwise indicates that this should be OK.
What do I need to change to make this work?
To get over the compilation error, you need:
return words.stream().collect(Collectors.toMap(word -> word, word -> 1));
however, this would result in all the values of the Map
being 1, and if you have duplicate elements in words
, you'll get an exception.
You'll need to either use Collectors.groupingBy
or Collectors.toMap
with a merge function to handle duplicate values.
For example
return words.stream().collect(Collectors.groupingBy(word -> word, Collectors.counting()));
or
return words.stream().collect(Collectors.toMap(word -> word, word -> 1, Integer::sum));