通过多个键平整流组的结果

时间:2019-02-14 15:32:32

标签: java java-8 java-stream

我想使用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]
 ]

3 个答案:

答案 0 :(得分:5)

您应该通过组合键进行分组,而不是使用级联的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.asList更改为List.of以创建组合键。

此方法非常适合您的情况,因为您表示对保留密钥不感兴趣,并且由于ListArrays.asList返回的List.of实现非常好-根据它们的equalshashCode方法进行定义,即可以安全地用作任何Map中的键。

答案 1 :(得分:0)

如果您想获得示例中的List<List<String>>,可以使用:

List<List<String>> list = collect.entrySet().stream()
            .flatMap(e -> e.getValue().entrySet().stream())
            .map(Map.Entry::getValue)
            .collect(Collectors.toList());

此外,如果要获取单个字符串列表,则可以再添加一个flatMap操作:

     ...
     .flatMap(e -> e.getValue().entrySet().stream())
     .flatMap(e -> e.getValue().stream())
     ...

就像@John Bollinger提到的那样,使用值流而不是条目会更简单。

答案 2 :(得分:0)

  

我想使用Java中的流将基于多个字段的长对象列表分组。

这比您的(无效)示例代码使我觉得您期望的要难得多。不过,您可以通过适当命名的flatMap()方法来平化流。对于您所描述的流,您可能需要多次展平或定义自定义映射方法或复杂的lambda,以一直展平到所要查找的内容。

对于问题中显示的表单的Map,您可以执行以下操作:

List<List<String>> result = myMap.values().stream()
        .flatMap(m -> m.values().stream())  // as many of these as needed
        .collect(Collectors.toList());