【问题标题】:Merge list of maps with duplicate keys [duplicate]合并具有重复键的地图列表[重复]
【发布时间】:2021-03-22 19:18:54
【问题描述】:

我有一个HashMap<Integer, ArrayList<String>> 列表,并希望将它们合并到一个循环中。 问题是每个地图的键都是从 0 开始的,所以键会被复制。 putAll() 不起作用,因为它会覆盖键并总是给我最后一张地图。

我已经看到了使用 Stream 合并两个地图的示例,但在我的情况下,可能有超过 2 个地图。我正在尝试生成具有增量键的合并映射。例如:

假设我在列表中有 2 个映射(可​​能更多),并且两个键都从 0 开始但以不同的值结束。

第一张地图,key从0开始到10结束

第二张地图,key从0开始到15结束

是否可以添加从 11 开始的密钥的第二张地图? 最后,我需要一个合并的映射,其中第一个键从 0 开始,最后一个键在 25 结束。

【问题讨论】:

  • HashMap 不允许重复键,因此它将覆盖键。您究竟想在这里实现什么输出?
  • 我假设你的意思是用相同的键合并映射条目的字符串列表?
  • @RajaShekar 编辑了问题以澄清我的需求。键应该是增量的。

标签: java dictionary collections merge stream


【解决方案1】:

我知道您要求提供地图,但根据您的解释,您的最终解决方案以及您的键现在是从 0 开始的连续整数这一事实,您可以只创建一个 List<List<String>>。在这种情况下,您可以这样做:

List<List<String>> result = mapList.stream()
               .flatMap(map->map.values().stream())
               .collect(Collectors.toList());                      

【讨论】:

    【解决方案2】:

    假设您有一个映射列表,其中每个映射的键是[0-k], [0-n], [0, r] ... 范围内的整数,并且您的结果映射应该在[0 - (k+n+r..)] 范围内设置一个键,如下所示应该可以:

    public static void main(String[] args) throws IOException {
       //example list of maps
       List<Map<Integer,List<String>>> mapList = List.of(
               Map.of( 0,List.of("foo","foo"), 
                       1,List.of("bar","bar"), 
                       2,List.of("baz","baz")),
               Map.of( 0,List.of("doo","doo"), 
                       1,List.of("gee","gee"), 
                       2,List.of("woo","woo")),
               Map.of( 0,List.of("cab","cab"), 
                       1,List.of("kii","kii"), 
                       2,List.of("taa","taa"))
       );
       AtomicInteger ai = new AtomicInteger();
       Map<Integer,List<String>> result = 
               mapList.stream()
                       .flatMap(map -> map.values().stream())
                       .collect(Collectors.toMap(list -> ai.getAndIncrement(), Function.identity()));
       result.forEach((k,v) ->{
           System.out.println(k + " : " + v);
       });
    }
    

    【讨论】:

    • @Cugomastik 欢迎您。很高兴我能帮忙
    【解决方案3】:

    如果您更喜欢流方法

    Map<Integer, List<String>> m1;
    Map<Integer, List<String>> m2;
    Map<Integer, List<String>> m3;
    
    Map<Integer, List<String>> combined = new HashMap<>();
    Stream
        .of(m1, m2, m3)
        .flatMap(m -> m.entrySet().stream())
        .forEach(e -> combined.computeIfAbsent(e.getKey(), k -> new ArrayList<>())
                .addAll(e.getValue()));
    

    【讨论】:

    • 感谢您的回答,但如果要合并 50 张地图怎么办?可以循环使用吗?
    • 如果是 50 个,我希望你会有一个它们的列表。然后你可以流式传输列表。 List&lt;Map&lt;Integer, List&lt;String&gt;&gt;&gt; maps。您可以使用 maps.stream() 后跟其余代码。
    • 非常感谢您的回答。我修改了代码并使用地图列表进行了尝试,但仍然只获得最后一张地图。
    • 在上面的示例中,您将在组合地图中找到所有条目。
    【解决方案4】:

    我会遍历您拥有的任意数量的地图,然后对于您想要组合的每个地图,遍历条目。对于每个条目,您可以使用computeIfAbsent 有条件地为键创建一个空列表,然后在值上调用addAll。例如:

    List<Map<Integer, List<String>>> maps = List.of(
            Map.of(1, List.of("hello")),
            Map.of(2, List.of("world")),
            Map.of(1, List.of("a"), 2, List.of("b"))
    );
    
    Map<Integer, List<String>> combined = new HashMap<>();
    for (Map<Integer, List<String>> map : maps) {
        for (Map.Entry<Integer, List<String>> e : map.entrySet()) {
            combined.computeIfAbsent(e.getKey(), k -> new ArrayList<>()).addAll(e.getValue());
        }
    }
    

    【讨论】:

    • 您好 Mureinik,非常感谢您的回答。不幸的是,地图没有合并,我仍然得到最后一张地图。
    • @Cugomastik 我建议在问题中提供minimal reproducible example。上面的代码确实将映射合并为一个(在 JShell 中工作)。
    猜你喜欢
    • 2020-01-22
    • 2021-01-06
    • 2019-12-15
    • 1970-01-01
    • 2022-11-25
    • 2013-12-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多