合并两个地图 与Java 8个流API 合并两个地图 与Java 8个流API(Mergi

2019-05-13 04:03发布

我有两个(或更多) Map<String, Integer>对象。 我想在价值观,共同的键应该是最大的值的方式与Java 8个流API来合并它们。

@Test
public void test14() throws Exception {
    Map<String, Integer> m1 = ImmutableMap.of("a", 2, "b", 3);
    Map<String, Integer> m2 = ImmutableMap.of("a", 3, "c", 4);
    List<Map<String, Integer>> list = newArrayList(m1, m2);

    Map<String, Integer> mx = list.stream()... // TODO

    Map<String, Integer> expected = ImmutableMap.of("a", 3, "b", 3, "c", 4);
    assertEquals(expected, mx);
}

我怎样才能让这种测试方法的绿色?

我已经打了collectCollectors了一段时间没有任何成功。

ImmutableMapnewArrayList来自谷歌番石榴)。

Answer 1:

@Test
public void test14() throws Exception {
    Map<String, Integer> m1 = ImmutableMap.of("a", 2, "b", 3);
    Map<String, Integer> m2 = ImmutableMap.of("a", 3, "c", 4);

    Map<String, Integer> mx = Stream.of(m1, m2)
        .map(Map::entrySet)          // converts each map into an entry set
        .flatMap(Collection::stream) // converts each set into an entry stream, then
                                     // "concatenates" it in place of the original set
        .collect(
            Collectors.toMap(        // collects into a map
                Map.Entry::getKey,   // where each entry is based
                Map.Entry::getValue, // on the entries in the stream
                Integer::max         // such that if a value already exist for
                                     // a given key, the max of the old
                                     // and new value is taken
            )
        )
    ;

    /* Use the following if you want to create the map with parallel streams
    Map<String, Integer> mx = Stream.of(m1, m2)
        .parallel()
        .map(Map::entrySet)          // converts each map into an entry set
        .flatMap(Collection::stream) // converts each set into an entry stream, then
                                     // "concatenates" it in place of the original set
        .collect(
            Collectors.toConcurrentMap(        // collects into a map
                Map.Entry::getKey,   // where each entry is based
                Map.Entry::getValue, // on the entries in the stream
                Integer::max         // such that if a value already exist for
                                     // a given key, the max of the old
                                     // and new value is taken
            )
        )
    ;
    */

    Map<String, Integer> expected = ImmutableMap.of("a", 3, "b", 3, "c", 4);
    assertEquals(expected, mx);
}


Answer 2:

Map<String, Integer> mx = new HashMap<>(m1);
m2.forEach((k, v) -> mx.merge(k, v, Integer::max));


Answer 3:

mx = list.stream().collect(HashMap::new,
        (a, b) -> b.forEach((k, v) -> a.merge(k, v, Integer::max)),
        Map::putAll);

这包括为任何规模大小列表一般情况下,应该与任何类型的工作,只是换出Integer::max和/或HashMap::new的期望。

如果你不关心它的值在合并出来的时候,有一个更清洁的解决方案:

mx = list.stream().collect(HashMap::new, Map::putAll, Map::putAll);

而作为一般的方法:

public static <K, V> Map<K, V> mergeMaps(Stream<? extends Map<K, V>> stream) {
    return stream.collect(HashMap::new, Map::putAll, Map::putAll);
}

public static <K, V, M extends Map<K, V>> M mergeMaps(Stream<? extends Map<K, V>> stream,
        BinaryOperator<V> mergeFunction, Supplier<M> mapSupplier) {
    return stream.collect(mapSupplier,
            (a, b) -> b.forEach((k, v) -> a.merge(k, v, mergeFunction)),
            Map::putAll);
}


Answer 4:

我创建的@srborlongan做了什么,任何人谁可能会感兴趣的可视化表示。



Answer 5:

我说我的贡献质子包库包含了流API实用方法。 这里是你如何能达到你想要什么:

Map<String, Integer> mx = MapStream.ofMaps(m1, m2).mergeKeys(Integer::max).collect();

基本上mergeKeys将收集在一个新的地图的键值对(提供合并功能是可选的,你会最终有一个Map<String, List<Integer>>其他方式)和召回stream()entrySet()到得到一个新的MapStream 。 然后使用collect()获取生成的地图。



Answer 6:

使用StreamEx你可以这样做:

StreamEx.of(m1, m2)
    .flatMapToEntry(x -> x)
    .grouping(IntCollector.max())


文章来源: Merging two Map with Java 8 Stream API