【问题标题】:Create Map based on two other maps in Java基于Java中的其他两个地图创建地图
【发布时间】:2018-07-09 19:21:11
【问题描述】:

如何使用 Java 8 流基于其他两个地图构建地图?即,我有以下地图结构:

map1 = Map<MyModel, List<String>>();
map2 = Map<String, String>();

其中map1List&lt;String&gt; 值与map2 中的String 键相同。换句话说,基于map1 values 可以将其用作map2 中的keys 并从那里获取values

那么,我的问题是如何使用流和 lambdas 技术合并这两个映射并构建一个新映射,其中将包含 MyModel as keysList&lt;Strings&gt; as values 而没有重复?

这是我目前所拥有的:

map1 = Map<MyModel, List<String>>();
map2 = Map<String, String>();

Map<MyModel, List<String>> map3 = Stream.of(map1, map2)
    .flatMap(map -> map.entrySet().stream())
    .collect(Collectors.toMap(
        Map.Entry::getKey,
        Map.Entry::getValue,
        (v1, v2) -> v1
    )
);

任何帮助将不胜感激。

【问题讨论】:

    标签: lambda java-8 java-stream map-function


    【解决方案1】:

    让我们开始通过查找 map2 的值并丢弃重复项来转换 List&lt;String&gt; list

    import static java.util.stream.Collectors.toList;
    import static java.util.stream.Collectors.toMap;
    .....
    
    list.stream()
        .filter(map2::containsKey)  // make sure map2 has this key
        .map(map2::get)             // get the value
        .distinct()                 // discard duplicates
        .collect(toList());         // make new list
    

    现在你只需要使用上面的作为值映射器(静态导入Collectors 方法)来解决你的问题:

    map1.entrySet().stream().collect(toMap(
        Map.Entry::getKey,
        e -> e.getValue().stream()
            .filter(map2::containsKey)
            .map(map2::get)
            .distinct()
            .collect(toList())
    ));
    

    【讨论】:

    • 不错的答案..非常简洁
    • 感谢您的回复。使用您建议的方法显示非静态方法无法从 Map.Entry::getKey 的静态上下文错误中引用,并且无法解析 e.getValue().stream() 的方法错误。
    • @Dozent 确保包含toListtoMap 的静态导入。见ideone.com/mxeRTf
    • @Misha,我以其他方式做到了,但在流范围内使用了您的技术。谢谢你的主意。它被接受了:D
    【解决方案2】:

    下面是我很快想到的。可能有一种更有效的方法来实现您的要求,但它至少会给您一个开始。

    代码

    public static void main(String[] args) {
        //Map 1
        Map<Integer, List<String>> map1 = new HashMap<>();
        map1.put(1, Arrays.asList("A", "B"));
        map1.put(2, Arrays.asList("C", "D"));
    
        //Map 2
        Map<String, String> map2 = new HashMap<>();
        map2.put("A", "Apple");
        map2.put("B", "Banana");
        map2.put("C", "Cherries");
        map2.put("D", "Dewberries");
    
        Map<Integer, List<String>> collect = map1.entrySet()
                .stream()
                .map(entry -> {
                    return new AbstractMap.SimpleImmutableEntry<>(
                            entry.getKey(),
                            entry.getValue()
                                    .stream()
                                    .map(map2::get)
                                    .filter(Objects::nonNull)
                                    .collect(Collectors.toList())
                    );
                })
                .collect(Collectors.toMap(AbstractMap.SimpleImmutableEntry::getKey, AbstractMap.SimpleImmutableEntry::getValue));
    
        System.out.println(collect);
    }
    

    输出

    {1=[Apple, Banana], 2=[Cherries, Dewberries]}
    

    【讨论】:

    • 使用entry.setValue会尝试修改源映射,这是很危险的。如果可以接受修改原件,最好使用map1.replaceAll( (k,v) -&gt; ....) 明确说明
    • 感谢@Misha 的反馈。我已经编辑了我的代码,不更新现有的 Map.Entry,而是创建并返回另一个对象。
    • @GarrethGolding,感谢您的回复,您的方法也有效!但是正如您在上面提到的那样,Misha 的回答既简洁又好;)
    猜你喜欢
    • 1970-01-01
    • 2021-02-10
    • 1970-01-01
    • 2014-11-10
    • 1970-01-01
    • 1970-01-01
    • 2012-08-28
    • 1970-01-01
    • 2013-01-22
    相关资源
    最近更新 更多