2016-02-28 73 views
3

合併地圖我在那裏每次迭代I'm創建一個新的地圖的Java 8中的迭代器

Map<String, List<String>> 

現在我想在每一個合併迭代用新的最後發射地圖的iteraror。

如果我送物品的列表getMap

{"a","a","b"} 

我希望收到地圖的

["a",{"foo:a", "foo:a"}, "b",{"foo:b"}] 

一個我試圖用減少功能,但由於的putAll只有工作,如果我使用多重映射而不是地圖,不是一個好的選擇。

這裏我的代碼

public Map<String, List<String>> getMap(List<String> items){ 
     return items().stream() 
       .map(item -> getNewMap(item) --> Return a Map<String, List<String>> 
       .reduce(new HashMap<>(), (o, p) -> { 
        o.putAll(p); 
        return o; 
       }); 
} 

public Map<String, List<String>> getNewMap(String item){ 
    Map<String, List<String>> map = new HashMap<>(); 
    map.put(item, Arrays.asList("foo:" + item)); 
    return map; 
}  

I'm找一個沒有詳細辦法做到這一點。

+1

不要考慮接受Holger的解決方案,而不是我的,它是一個更清潔,更好。 – Tunaki

回答

4

你想要的是將每個中間映射平面映射到它的條目,並製作一個映射。

在下面的代碼中,每個項目都映射到其對應的映射。然後,將每個地圖平面映射到其條目,並將流收集到地圖中。

public static void main(String[] args) { 
    System.out.println(getMap(Arrays.asList("a", "a", "b"))); 
    // prints "{a=[foo:a, foo:a], b=[foo:b]}" 
} 

public static Map<String, List<String>> getMap(List<String> items) { 
    return items.stream() 
       .map(item -> getNewMap(item)) 
       .flatMap(m -> m.entrySet().stream()) 
       .collect(Collectors.toMap(
        Map.Entry::getKey, 
        Map.Entry::getValue, 
        (l1, l2) -> { List<String> l = new ArrayList<>(l1); l.addAll(l2); return l; } 
       )); 
} 

public static Map<String, List<String>> getNewMap(String item) { 
    Map<String, List<String>> map = new HashMap<>(); 
    map.put(item, Arrays.asList("foo:" + item)); 
    return map; 
} 

在多個鍵的情況下,這將每個列表附加在一起。

+0

工程很不錯,謝謝你的這一課。 – paul

+0

生成地圖只是爲了平面地圖生成的地圖產生了令人印象深刻的代碼,展示了流API的所有功能,但我認爲OP的初始方法已將您誤導爲此巴洛克式解決方案。從零開始並使用正確的工具導致[更簡單的解決方案](http://stackoverflow.com/a/35699445/2711488)。最後,請注意,如果您確實需要單個條目'Map',請考慮['singletonMap'](https://docs.oracle.com/javase/8/docs/api/java/util/Collections.html #singletonMap-KV-)... – Holger

+0

@Holger對於這個特定的實例,你是正確的,它可以做得更簡單。但是如果內部地圖是「[foo:...,bar:...]」呢? – Tunaki

4

無論何時您想從流中獲得Map<…, List<…>>,您都應該首先檢查groupingBy collector如何適用。最簡單的形式是,它接收一個分組函數,該函數確定結果映射的鍵,並收集所有元素一個組成一個列表。既然你想要的前綴"foo:"預謀,你會被插入mapping operationcollecting the items into a list必須customize this group collector

public static Map<String, List<String>> getMap(List<String> items) { 
    return items.stream().collect(Collectors.groupingBy(
     Function.identity(), 
     Collectors.mapping("foo:"::concat, Collectors.toList()))); 
} 

分類函數本身是身份的功能微不足道,只要你想建立一個組的所有相等的元素。

+0

感謝您的新解決方案。但關於「foo:」+項目的concat只是示例的一部分,實際上我們並沒有在真正的代碼中這樣做。我會盡快查看該解決方案。 – paul

+0

無論您使用'「foo:」:: concat'還是'x - >「foo:」+ x'或任何您喜歡的映射函數,都無關緊要。邏輯不會改變。 – Holger

+0

getNewMap()只是一個示例方法,它真正的應用程序返回一個Map >,它具有更復雜的業務邏輯,所以Collectors.mapping(Function)看起來不可能。但是我會研究你的代碼,我會看看是否可以使用它。再次感謝。 – paul