Java 8 Stream函数可将字谜列表组合为列表映射 [英] Java 8 Stream function to group a List of anagrams into a Map of Lists

查看:43
本文介绍了Java 8 Stream函数可将字谜列表组合为列表映射的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Java 8即将发布...在学习Streams的同时,我进入了一个场景,该场景使用一种新方法对字谜进行分组.我面临的问题是我找不到使用map/reduce函数对Strings对象进行分组的方法.取而代之的是,我必须创建一种与聚合操作-减少所述相似的方式..

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的映射.

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);
}

这篇关于Java 8 Stream函数可将字谜列表组合为列表映射的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆