The single-argument groupingBy
collector does exactly what you want to do. It classifies its input, which you've already done using sortChars
(or getKey
in the earlier example). Each stream value that's classified under the same key gets put into a list which is the map's value. Thus we have:
Map<String, List<String>> anagrams =
words2.stream().collect(Collectors.groupingBy(w -> sortChars(w)));
giving the output
{door=[odor, rood], acr=[arc, car], ghint=[night, thing], aemrst=[stream],
efirs=[fires, fries], loop=[pool, loop], aemst=[meats, mates, teams]}
You could also use a method reference:
Map<String, List<String>> anagrams =
words2.stream().collect(Collectors.groupingBy(GroupingAnagrams::sortChars));
If you want to do something with the values other than building up a list, use a multi-arg overload of groupingBy
and a "downstream" collector. For example, to count the words instead of building up a list, do this:
Map<String, Long> anagrams =
words2.stream().collect(
Collectors.groupingBy(GroupingAnagrams::sortChars, Collectors.counting()));
This results in:
{door=2, acr=2, ghint=2, aemrst=1, efirs=2, loop=2, aemst=3}
EDIT:
In case it wasn't clear, sortChars
is simply a static function that performs a similar function to what getKey
did in the first example, but from string to string:
public static String sortChars(String input) {
char[] characters = input.toCharArray();
Arrays.sort(characters);
return new String(characters);
}