我希望使用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]
]
发布于 2019-02-14 07:44:15
与其使用级联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
来创建复合键。
这种方法对您的情况非常有效,因为您说您对保留密钥不感兴趣,并且因为Arrays.asList
和List.of
返回的List.of
实现在其equals
和hashCode
方法中都有很好的定义,也就是说它们可以在任何Map
中安全地用作密钥。
发布于 2019-02-14 07:42:32
如果您想获得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())
...
正如@所提到的,使用值流,但不使用条目会更简单。
发布于 2019-02-14 07:46:07
我希望使用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());
https://stackoverflow.com/questions/54693923
复制相似问题