簡體   English   中英

使用 Java 8 Lambda 表達式合並 Map 流

[英]Merging Map streams using Java 8 Lambda Expression

我有兩個Map<Integer, String>類型的映射m1m2 ,它們必須合並到一個映射Map<Integer, List<String>> ,其中兩個映射中相同鍵的值被收集到一個 List 和放入新地圖。

基於我探索的解決方案:

Map<Integer, List<String>> collated =
        Stream.concat(m1.entrySet().stream(), m2.entrySet().stream()).collect(
                Collectors.toMap(Entry::getKey,
                        Entry::getValue, (a, b) -> {
                            List<String> merged = new ArrayList<String>(a);
                            merged.addAll(b);
                            return merged;
                        }));

但是,這個解決方案期望源ListMap<Integer, List<String>>因為 toMap 中的合並函數期望操作數和結果是相同的類型。

我不想更改源集合。 請提供有關使用 lambda 表達式實現此目標的輸入。

這是groupingBy收集器的工作:

Stream.of(m1,m2)
        .flatMap(m->m.entrySet().stream())
        .collect(groupingBy(
                Map.Entry::getKey,
                mapping(Map.Entry::getValue, toList())
        ));

我現在不能測試它,但我認為你需要它來將值的映射從Entry::getValue更改為包含該值的 List :

Map<Integer, List<String>> collated =
        Stream.concat(m1.entrySet().stream(), m2.entrySet().stream())
                .collect(Collectors.toMap(Entry::getKey,
                        e -> {
                            List<String> v = new ArrayList<String>();
                            v.add(e.getValue());
                            return v;
                        },
                        (a, b) -> {
                            List<String> merged = new ArrayList<String>(a);
                            merged.addAll(b);
                            return merged;
                        }));

編輯:這個想法是正確的。 語法不是。 當前語法有效,雖然有點難看。 必須有一種更短的方式來編寫它。

您還可以將e -> {..}替換為e -> new ArrayList<String>(Arrays.asList(new String[]{e.getValue()}))

或使用e -> Stream.of(e.getValue()).collect(Collectors.toList())

或者你可以用groupingBy來做到:

Map<Integer, List<String>> collated =
        Stream.concat(m1.entrySet().stream(), m2.entrySet().stream())
                .collect(Collectors.groupingBy(Map.Entry::getKey,
                        Collectors.mapping(Map.Entry::getValue,
                                Collectors.toList())));

如果您想要純 Java-8 解決方案,Misha 的解決方案是最好的。 如果您不介意使用第三方庫,那么使用我的StreamEx會短一些

Map<Integer, List<String>> map = StreamEx.of(m1, m2)
        .flatMapToEntry(Function.identity())
        .grouping();

在內部,它與 Misha 的解決方案相同,只是語法糖。

這似乎是使用 Guava 的Multimap的絕佳機會。

ListMultimap<Integer, String> collated = ArrayListMultimap.create();
collated.putAll(Multimaps.forMap(m1));
collated.putAll(Multimaps.forMap(m2));

如果你真的需要一個Map<Integer, List<String>>

Map<Integer, List<String>> mapCollated = Multimaps.asMap(collated);

為清楚起見,您可以使用帶有三個參數的Collectors.toMap方法。

Map<Integer, String> m1 = Map.of(1, "A", 2, "B");
Map<Integer, String> m2 = Map.of(1, "C", 2, "D");
// two maps into one
Map<Integer, List<String>> m3 = Stream
        .of(m1.entrySet(), m2.entrySet())
        .flatMap(Collection::stream)
        .collect(Collectors.toMap(
                // key - Integer
                e -> e.getKey(),
                // value - List<String>
                e -> List.of(e.getValue()),
                // mergeFunction - two lists into one
                (list1, list2) -> {
                    List<String> list = new ArrayList<>();
                    list.addAll(list1);
                    list.addAll(list2);
                    return list;
                }));
// output
System.out.println(m3); // {1=[A, C], 2=[B, D]}

暫無
暫無

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

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