如何正确使用 Map <String, StringBuilder> 的 merge() 方法追加特定字符?

How to correctly use the method merge() of Map <String, StringBuilder> to append a specific character?

我有以下地图:

Map<String, StringBuilder> map1 = new HashMap<>();
Map<String, StringBuilder> map2 = new HashMap<>();

StringBuilder sb11 = new StringBuilder("0004001:00:00;0004002:00:00;0004002:01:01;");
StringBuilder sb12 = new StringBuilder("0005001:00:00;0005002:00:00;0005002:01:01;");
StringBuilder sb13 = new StringBuilder("0007001:00:00;0007002:00:00;0007002:01:01;");
  
map1.put("0004", sb11);
map1.put("0005", sb12);
map1.put("0007", sb13);
  
StringBuilder sb21 = new StringBuilder("0004002:00:00;0004002:00:00;0004002:01:01;");
StringBuilder sb22 = new StringBuilder("0007002:00:00;0007002:00:00;0007002:01:01;");
StringBuilder sb23 = new StringBuilder("0008002:00:00;0008002:00:00;0008002:01:01;");
  
map2.put("0004", sb21);
map2.put("0007", sb22);
map2.put("0008", sb23);

在这些映射的基础上,我需要获得一个结果映射,对于上面两个映射中的相同键,具有由“|”分隔的值的串联。

对于不同的键,也必须满足条件 - 如果键仅存在于 map1 中,则仅添加值,如果键仅存在于 map2 中,则添加“|”应在值之前添加。简而言之,我的意思是这个结果:

地图1

0004 - 0004001:00:00;0004002:00:00;0004002:01:01;
0005 - 0005001:00:00;0005002:00:00;0005002:01:01;
0007 - 0007001:00:00;0007002:00:00;0007002:01:01;

map2

0004 - 0004002:00:00;0004002:00:00;0004002:01:01;
0007 - 0007002:00:00;0007002:00:00;0007002:01:01;
0008 - 0008002:00:00;0008002:00:00;0008002:01:01;

预期结果图

0004 - 0004001:00:00;0004002:00:00;0004002:01:01;|0004002:00:00;0004002:00:00;0004002:01:01;
0005 - 0005001:00:00;0005002:00:00;0005002:01:01;
0007 - 0007001:00:00;0007002:00:00;0007002:01:01;|0007002:00:00;0007002:00:00;0007002:01:01;
0008 - |0008002:00:00;0008002:00:00;0008002:01:01;

我几乎找到了一个解决方案,但我遇到了一个问题,当密钥只存在于 map2 中时,我不知道如何更改我的代码以使“|”在值前添加符号。

我该如何解决?

我的代码:

public static void main(String args[]) {

    Map<String, StringBuilder> map1 = new HashMap<>();
    Map<String, StringBuilder> map2 = new HashMap<>();

    StringBuilder sb11 = new StringBuilder("0004001:00:00;0004002:00:00;0004002:01:01;");
    StringBuilder sb12 = new StringBuilder("0005001:00:00;0005002:00:00;0005002:01:01;");
    StringBuilder sb13 = new StringBuilder("0007001:00:00;0007002:00:00;0007002:01:01;");
      
    map1.put("0004", sb11);
    map1.put("0005", sb12);
    map1.put("0007", sb13);
      
    StringBuilder sb21 = new StringBuilder("0004002:00:00;0004002:00:00;0004002:01:01;");
    StringBuilder sb22 = new StringBuilder("0007002:00:00;0007002:00:00;0007002:01:01;");
    StringBuilder sb23 = new StringBuilder("0008002:00:00;0008002:00:00;0008002:01:01;");
      
    map2.put("0004", sb21);
    map2.put("0007", sb22);
    map2.put("0008", sb23);

      
      //Merge maps
      map2.forEach((key, value) -> map1.merge(key, value, (v1, v2) -> v1.append("|").append(v2)));
      
      map1.entrySet().forEach(entry->{
        System.out.println(entry.getKey() + " " + entry.getValue());  
    });
}

结果:

0007 0007001:00:00;0007002:00:00;0007002:01:01;|0007002:00:00;0007002:00:00;0007002:01:01;
0004 0004001:00:00;0004002:00:00;0004002:01:01;|0004002:00:00;0004002:00:00;0004002:01:01;
0005 0005001:00:00;0005002:00:00;0005002:01:01;
0008 0008002:00:00;0008002:00:00;0008002:01:01;

merge 根本无法完成这项工作。如果 map1map2 都具有提供的密钥,merge 调用该函数;否则,如果两个映射中只有一个具有该键的映射,则只插入该映射而不进行修改——因此,没有前导 |。没有办法让 merge 以不同的方式工作,所以你不能在这里使用它。摆脱它。

像往常一样,如果你只在看起来很明显的地方使用 lambda,而不是像万能的锤子那样好用到你想用它来做任何事情,包括给面包涂黄油,那么阅读起来会更简单。

for (var entry : map2.entrySet()) {
     map1
       .computeIfAbsent(entry.getKey(), x -> new StringBuilder())
       .append("|")
       .append(entry.getValue());
}

足够简单,并且完全符合您的要求。

如果你真的铁了心要用那把锤子来涂抹这片面包,你真正想要的方法是compute。不过,您将不得不摆弄 null,它不会更漂亮。

注意:collection.forEachcollection.stream.forEach 都是糟糕的代码风格——你失去了局部变量、控制流和异常透明度,而且你在交易中一无所获。为什么选择严格劣等的选项?如果您发现转储是可以接受的,例如someList.forEach(System.out::println); 在一行中,我很难想象你可能愿意提供什么样的非疯狂论点来禁止 for (var v : someList) System.out.println(v);,它同样简短,并且处理本地变量,控制流程和检查异常要好得多。我已经帮您移除了那个钻头。正如我所说,当它们为您提供有形的东西时使用 lambda,例如上面的 computeIfAbsent。如果没有它们,那会更加复杂。

好吧,这就是我的想法。它只是遍历一个地图,检查键并将适当的值放入另一个地图。如果每个map包含相同的key,则put,都在map1中,用|分隔,否则,将map2 keyvalue放在[=13=中] 与 prefixed|.

for(String key : map2.keySet()) {
    if (map1.containsKey(key)) {
        map1.put(key, map1.get(key).append("|").append(map2.get(key)));
    } else {
        map1.put(key, map2.get(key).insert(0, "|"));
    }
}
    
map1.entrySet().forEach(System.out::println);

版画

0007=0007001:00:00;0007002:00:00;0007002:01:01;|0007002:00:00;0007002:00:00;0007002:01:01;
0004=0004001:00:00;0004002:00:00;0004002:01:01;|0004002:00:00;0004002:00:00;0004002:01:01;
0005=0005001:00:00;0005002:00:00;0005002:01:01;
0008=|0008002:00:00;0008002:00:00;0008002:01:01;

如果您希望它们按键排序,则将 map1 设为 TreeMap