Java 8 Stream 函数将字谜列表分组为列表映射
Java 8 即将发布...在学习 Streams 时,我遇到了一个关于使用一种新方法对字谜进行分组的场景.我面临的问题是我找不到使用 map/reduce 函数对字符串对象进行分组的方法.相反,我必须创建与 Aggregate Operations - Reduction 中记录的类似方式.
Java 8 is about to be released... While learning about Streams, I got into a scenario about grouping anagrams using one of the new ways. The problem I'm facing is that I can't find a way to group Strings objects using the map/reduce functions. Instead, I had to create a similar way as documented at Aggregate Operations - Reduction.
根据文档,我们可以简单地使用:
Based on the documentation, we can simply use:
LIST<T>.stream().collect(Collectors.groupingBy(POJO::GET_METHOD))
这样 Collectors.groupingBy()
将根据使用的方法聚合地图的键.但是,这种方法对于包装简单的 String 表示似乎太麻烦了.
So that Collectors.groupingBy()
will aggregate the keys of the map based on the method used. However, this approach is too seems to be cumbersome to wrap a simple String presentation.
public class AnagramsGrouping {
static class Word {
public String original;
public Word(String word) {
original = word;
}
public String getKey() {
char[] characters = input.toCharArray();
Arrays.sort(characters);
return new String(characters);
}
public String toString() {
return original;
}
}
public static void main(String[] args) {
List<Word> words = Arrays.asList(new Word("pool"), new Word("loop"),
new Word("stream"), new Word("arc"), new Word("odor"),
new Word("car"), new Word("rood"), new Word("meats"),
new Word("fires"), new Word("fries"), new Word("night"),
new Word("thing"), new Word("mates"), new Word("teams"));
Map<String, List<Word>> anagrams = words.stream().collect(
Collectors.groupingBy(Word::getKey));
System.out.println(anagrams);
}
}
这将打印以下内容:
{door=[odor, rood], acr=[arc, car], ghint=[night, thing],
aemrst=[stream], efirs=[fires, fries], loop=[pool, loop],
aemst=[meats, mates, teams]}
相反,我正在寻找一种更简单、更直接的解决方案,它使用新的 map/reduce 函数将结果累积到类似的接口 Map<String, List<String>
.基于如何将列表转换为地图,我有以下内容:
Instead, I'm looking for a simpler and more direct solution that uses the new map/reduce functions to accumulate the results into the similar interface Map<String, List<String>
. Based on How to convert List to Map, I have the following:
List<String> words2 = Arrays.asList("pool", "loop", "stream", "arc",
"odor", "car", "rood", "meats", "fires", "fries",
"night", "thing", "mates", "teams");
words2.stream().collect(Collectors.toMap(w -> sortChars(w), w -> w));
但是这段代码会产生一个键冲突,因为它是一个 1-1 的 Map.
But this code generates a key collision as it is a Map of 1-1.
Exception in thread "main" java.lang.IllegalStateException: Duplicate key pool
这是有道理的...有没有办法将它们分组到与 groupingBy
的第一个解决方案类似的输出中,但不使用包装值的 POJO?
which makes sense... Is there a way to group them into the similar output as the first solution with groupingBy
, but without using a POJO wrapping the values?
推荐答案
单参数 groupingBy
收集器完全符合您的要求.它对其输入进行分类,您已经使用 sortChars
(或前面示例中的 getKey
)完成了这些工作.归类在同一键下的每个流值都被放入一个列表中,该列表是映射的值.因此我们有:
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)));
给出输出
{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));
如果您想对这些值做一些事情而不是建立一个列表,请使用 groupingBy
的多参数重载和下游"收集器.例如,要计算单词而不是建立一个列表,请执行以下操作:
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()));
这会导致:
{door=2, acr=2, ghint=2, aemrst=1, efirs=2, loop=2, aemst=3}
如果不清楚,sortChars
只是一个静态函数,它执行与第一个示例中的 getKey
类似的功能,但从字符串到字符串:
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);
}
相关文章