簡體   English   中英

使用Java 8 Streams將地圖Map轉換為列表

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

我有一張地圖:

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

Outcome:
List<Id>
List<ReferenceId>

我想將此地圖轉換為兩個整數列表。 一個列表包含內部映射鍵,另一個列表包含內部映射值(即List<Integer>

誰能告訴我如何使用流在Java 8中做到這一點?

我嘗試過這種方式,但遇到了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>

沒辦法,你的代碼如何

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

可以產生ClassCastException ,除非您設法在Stream操作之前通過未經檢查的操作將錯誤類型的對象插入源映射。 這種情況稱為堆污染 ,您應該在啟用所有警告的情況下編譯整個代碼( javac :使用選項-Xlint:unchecked )並解決它們。

但是請注意,您的代碼不必要地復雜。 .entrySet().stream().map(e -> e.getKey())在條目上進行流傳輸並映射到鍵,因此您可以首先在鍵上進行流傳輸,即.keySet().stream() 然后,將流收集到List ,只是為了在隨后的flatMap步驟中調用.stream() ,因此您可以簡單地使用已有的流來代替:

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

或者,您可以讓收集器完成所有工作:

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

獲取值而不是鍵的工作原理類似,但是需要另一個flatMap步驟來獲取List元素:

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

相當於

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

同樣,也可以讓收集器完成所有工作:

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

要么

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

如果您的值類似於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())

有用

為另一種工作方案添加

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

檢索邏輯

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

結果將是

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM