简体   繁体   English

使用Java 8 Streams将地图Map转换为列表

[英]Convert Map of maps into Lists using Java 8 Streams

I have a map: 我有一张地图:

Map<String, Map<Integer, List<Integer>>>
e.g. Map<Name, Map<Id, List<ReferenceId>>>

Outcome:
List<Id>
List<ReferenceId>

I wanna convert this map into two list of Integers. 我想将此地图转换为两个整数列表。 One list contains inner-map keys, and other contains inner-map value (ie List<Integer> ) 一个列表包含内部映射键,另一个列表包含内部映射值(即List<Integer>

Can anyone tell me how to do this in Java 8 using streams? 谁能告诉我如何使用流在Java 8中做到这一点?

I tried this way but got Cast Exception, can not convert String to Integer. 我尝试过这种方式,但遇到了Cast Exception,无法将String转换为Integer。

map.values().stream()
    .map(m -> m.entrySet()
    .stream()
    .map(e -> e.getKey())
    .collect(Collectors.toList()))
    .flatMap(l -> l.stream())
    .collect(Collectors.toList());
Map<String, Map<Integer, List<Integer>>> map = ...

List<Integer> keys = map.values()       // Collection<Map<Integer, List<Integer>>>
        .stream()                       // Stream<Map<Integer, List<Integer>>>
        .map(Map::keySet)               // Stream<Set<Integer>>
        .flatMap(Set::stream)           // Stream<Integer>
        .collect(Collectors.toList());  // List<Integer>

List<Integer> values = map.values()     // Collection<Map<Integer, List<Integer>>>
        .stream()                       // Stream<Map<Integer, List<Integer>>>
        .map(Map::values)               // Stream<Collection<List<Integer>>>
        .flatMap(Collection::stream)    // Stream<List<Integer>>
        .flatMap(List::stream)          // Stream<Integer>
        .collect(Collectors.toList());  // List<Integer>

There is no way, how your code 没办法,你的代码如何

List<Integer> list = map.values().stream()
    .map(m -> m.entrySet().stream()
            .map(e -> e.getKey())
            .collect(Collectors.toList()))
    .flatMap(l -> l.stream())
    .collect(Collectors.toList());

can produce a ClassCastException , unless you managed to insert objects of wrong type into the source map via unchecked operation(s) before the Stream operation. 可以产生ClassCastException ,除非您设法在Stream操作之前通过未经检查的操作将错误类型的对象插入源映射。 Such a situation is called heap pollution and you should compile your entire code with all warnings enabled ( javac : use option -Xlint:unchecked ) and solve them. 这种情况称为堆污染 ,您应该在启用所有警告的情况下编译整个代码( javac :使用选项-Xlint:unchecked )并解决它们。

But note that your code is unnecessarily complicated. 但是请注意,您的代码不必要地复杂。 The chain, .entrySet().stream().map(e -> e.getKey()) is streaming over the entries and mapping to the keys, so you can stream over the keys in the first place, ie .keySet().stream() . .entrySet().stream().map(e -> e.getKey())在条目上进行流传输并映射到键,因此您可以首先在键上进行流传输,即.keySet().stream() Then, you are collecting the stream into a List , just to invoke .stream() in the subequent flatMap step, so you can simply use the stream you already have instead: 然后,将流收集到List ,只是为了在随后的flatMap步骤中调用.stream() ,因此您可以简单地使用已有的流来代替:

List<Integer> list = map.values().stream()
    .flatMap(m -> m.keySet().stream())
    .collect(Collectors.toList());

Alternatively, you can let the collector do all the work: 或者,您可以让收集器完成所有工作:

List<Integer> list = map.values().stream()
    .collect(ArrayList::new, (l,m) -> l.addAll(m.keySet()), List::addAll);

Getting the values instead of the keys works similar, but requires another flatMap step to get the List elements: 获取值而不是键的工作原理类似,但是需要另一个flatMap步骤来获取List元素:

List<Integer> list = map.values().stream()
    .flatMap(m -> m.values().stream().flatMap(List::stream))
    .collect(Collectors.toList());

which is equivalent to 相当于

List<Integer> list = map.values().stream()
    .flatMap(m -> m.values().stream())
    .flatMap(List::stream)
    .collect(Collectors.toList());

Again, there's the alternative of letting the collector do all the work: 同样,也可以让收集器完成所有工作:

List<Integer> list = map.values().stream()
    .collect(ArrayList::new, (l,m)->m.values().forEach(l::addAll), List::addAll);

or 要么

List<Integer> list = map.values().stream()
    .collect(ArrayList::new, (l,m)->m.forEach((k,v)->l.addAll(v)), List::addAll);

If your value is like Map<String,Object> . 如果您的值类似于Map<String,Object> And your Object is like Map<String,Object> : 和您的Object就像Map<String,Object>

 Set<String> mapKeys = myMap.entryset()    //Set<Entry<String,Object>>
.stream()                                  //Stream<Entry<String,Object>>
.map(m->(Map<String,Object>) m.getValue()) //Stream<Map<String,Object>>
.map(Map::keySet)                          //Stream<Set<String>>
.flatMap(l->l.stream())                    //Stream<String>
.collect(Collectors.toSet())

it works 有用

Adding for one more working scenario 为另一种工作方案添加

 Map<Integer, List<Integer>> existingPacakagesMap = // having value {123=[111, 222, 333], 987=[444, 555, 666]}

Retrieving logic 检索逻辑

 List<Integer>   ListOfAllPacakages= existingPacakagesMap.values().stream().flatMap(List::stream).collect(Collectors.toList());

Result will be 结果将是

ListOfAllPacakages= [111, 222, 333, 444, 555, 666] ListOfAllPacakages = [111、222、333、444、555、666]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM