首页 > 解决方案 > 多键串流分组

问题描述

我想在 java 中使用流来根据多个字段对长长的对象列表进行分组。这将导致地图地图地图地图地图地图地图地图地图。

我怎样才能只从那个复杂的流中提取列表?

这是一些演示示例代码(字符串列表,寻找具有相同长度和首字母的组)。我对键不感兴趣,只对结果分组的实体感兴趣。

List<String> strings = ImmutableList.of("A", "AA", "AAA", "B", "BB", "BBB", "C", "CC", "CCC", "ABA", "BAB", "CAC");

Map<Character, Map<Integer, List<String>>> collect = strings.stream().collect(
        groupingBy(s -> s.charAt(0),
                groupingBy(String::length)
        )
);

这将产生以下结果

My Map =
{
    A =
    {
        1 = [A]
        2 = [AA]
        3 = [AAA, ABA]
    }
    B =
    {
        1 = [B]
        2 = [BB]
        3 = [BBB, BAB]
    }
    C =
    {
        1 = [C]
        2 = [CC]
        3 = [CCC, CAC]
    }
}

我感兴趣的实际上只是上述结果中的列表,我想在理想情况下将其作为 groupby 操作的一部分。我知道它可以通过例如循环生成的地图结构来完成。但是有没有办法使用流来实现它?

 [
     [A],
     [AA],
     [AAA, ABA],
     [B],
     [BB],
     [BBB, BAB],
     [C],
     [CC],
     [CCC, CAC]
 ]

标签: javajava-8java-stream

解决方案


而不是使用 cascaded 创建嵌套组Collectors.groupingBy,您应该按复合键进行分组:

Map<List<Object>, List<String>> map = strings.stream()
        .collect(Collectors.groupingBy(s -> Arrays.asList(s.charAt(0), s.length())));

然后,只需获取地图值:

List<List<String>> result = new ArrayList<>(map.values());

如果您使用的是 Java 9+,您可能需要从 更改Arrays.asListList.of来创建复合键。

这种方法非常适合您的情况,因为您声明您对保留密钥不感兴趣,并且因为List两者返回的实现Arrays.asList并且在它们和方法List.of方面都有很好的定义,即它们可以安全地用作任何密钥.equalshashCodeMap


推荐阅读