如何解决如何将多个地图与多个相同的键和列表组合为值?
我是 Java 新手,我正在尝试合并多个映射,以字符串为键,以列表为值,以生成新的映射。
public class Student {
private String name;
private String country;
//Setters and Getters
}
现在我有一个 util 类,可以根据学生所在的国家/地区将他们添加到列表中。
public class MapAdder {
static Map<String,List<Student>> studentMap =
new LinkedHashMap<String,List<Student>>();
public static void addToMap(String key,Student student) {
studentMap.computeIfAbsent(key,k -> new LinkedList<Student>()).add(student);
}
public static Map<String,List<Student>> getStudentMap() {
return studentMap;
}
public static void clearStudentMap() {
studentMap.clear();
}
}
主要方法
public static void main(String[] args) {
Map<String,List<Student>> studentMap1;
Map<String,List<Student>> studentMap2;
Map<String,List<Student>> studentMap3;
MapAdder.addToMap("India",new Student("Mounish","India"));
MapAdder.addToMap("USA",new Student("Zen","USA"));
MapAdder.addToMap("India",new Student("Ram",new Student("Ronon","USA"));
MapAdder.addToMap("UK",new Student("Tony","UK"));
studentMap1 = MapAdder.getStudentMap();
MapAdder.clearStudentMap();
MapAdder.addToMap("India",new Student("Rivar","India"));
MapAdder.addToMap("UK",new Student("Loki","UK"));
MapAdder.addToMap("UK",new Student("Imran","UK"));
MapAdder.addToMap("USA",new Student("ryan","USA"));
studentMap2 = MapAdder.getStudentMap();
MapAdder.clearStudentMap();
Map<String,List<Student>> map3 = Stream.of(studentMap1,studentMap2)
.flatMap(map -> map.entrySet().stream())
.collect(Collectors.toMap(
Entry::getKey,Entry::getValue
));
}
但是当我尝试合并两张地图时,我得到了空地图。 实际上,我需要一个包含三个键(印度、英国、美国)及其值的地图,这些值是从要合并到键的多个地图中列出的。
解决方法
首先,从您的代码中删除以下调用:
MapAdder.clearStudentMap();
您正在清除 studentMap1
和 studentMap2
。
当你这样做时:
studentMap1 = MapAdder.getStudentMap();
您将获得存储学生 Map
的内存引用。当您在该地图上调用 clear
方法时
studentMap.clear();
您将清除存储在同一内存引用上的所有 Map
条目。换句话说,下面的语句
studentMap1 = MapAdder.getStudentMap();
不创建学生 Map
的副本,而只是将对该 Map 的内存引用保存在变量 studentMap1
中。
您的 Stream 方法几乎是正确的,请将其更改为:
Map<String,List<Student>> map3 = Stream.of(studentMap1,studentMap2)
.flatMap(map -> map.entrySet().stream())
.collect(Collectors.toMap(
Map.Entry::getKey,e -> new ArrayList<>(e.getValue()),(left,right) -> { left.addAll(right); return left; }
));
您还需要添加用于处理重复键的策略(即 mergeFunction
方法的 Collectors.toMap
参数)。在重复键的情况下,我们将 Map 值添加到 left 键的列表中。
顺便说一下,我删除了一些辅助方法,它们混淆了代码,并通过将 addToMap
本身作为参数传递来使 Map
方法更加通用,这样您就可以使用不同的映射器重用该方法,即:
public class MapAdder {
public static void addToMap(Map<String,List<Student>> studentMap,String key,Student student) {
studentMap.computeIfAbsent(key,k -> new LinkedList<Student>()).add(student);
}
public static void main(String[] args) {
Map<String,List<Student>> studentMap1 = new LinkedHashMap<>();
Map<String,List<Student>> studentMap2 = new LinkedHashMap<>();
Map<String,List<Student>> studentMap3;
MapAdder.addToMap(studentMap1,"India",new Student("Mounish","India"));
MapAdder.addToMap(studentMap1,"USA",new Student("Zen","USA"));
MapAdder.addToMap(studentMap1,new Student("Ram",new Student("Ronon","UK",new Student("Tony","UK"));
MapAdder.addToMap(studentMap2,new Student("Rivar","India"));
MapAdder.addToMap(studentMap2,new Student("Loki","UK"));
MapAdder.addToMap(studentMap2,new Student("Imran",new Student("ryan","USA"));
Map<String,studentMap2)
.flatMap(map -> map.entrySet().stream())
.collect(Collectors.toMap(
Map.Entry::getKey,right) -> { left.addAll(right); return left; }
));
}
}
,
在创建 HashMap
实例时,您可以覆盖其 put
和 putAll
方法,这样它们就不会替换现有值,而是附加它们,即合并值列表相同的键:
Map<String,List<Student>> studentMap = new HashMap<>() {
@Override
public List<Student> put(String key,List<Student> value) {
if (this.containsKey(key)) {
List<Student> val = this.get(key);
val.addAll(value);
return val;
} else {
return super.put(key,new ArrayList<>(value));
}
}
@Override
public void putAll(Map<? extends String,? extends List<Student>> m) {
Iterator<? extends Entry<? extends String,? extends List<Student>>>
iterator = m.entrySet().iterator();
while (iterator.hasNext()) {
Entry<? extends String,? extends List<Test.Student>>
e = iterator.next();
this.put(e.getKey(),e.getValue());
}
}
};
studentMap.put("India",List.of(new Student("Mounish","India")));
studentMap.put("USA",List.of(new Student("Zen","USA")));
studentMap.putAll(Map.of(
"India",List.of(new Student("Ram","India")),List.of(new Student("Ronon","USA")),List.of(new Student("Tony","UK"))));
studentMap.putAll(Map.of(
"India",List.of(new Student("Rivar",List.of(new Student("Loki","UK"))));
studentMap.putAll(Map.of(
"UK",List.of(new Student("Imran","UK")),List.of(new Student("ryan","USA"))));
studentMap.forEach((k,v) -> System.out.println(k + "=" + v));
// USA=[Zen:USA,Ronon:USA,ryan:USA]
// UK=[Tony:UK,Loki:UK,Imran:UK]
// India=[Mounish:India,Ram:India,Rivar:India]
如果你不再需要这个扩展功能,你可以放弃它并返回到常规地图:
studentMap = new HashMap<>(studentMap);
另见:The 'contains' method does not work for ArrayList<int[]>,is there another way?
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。