我是Java新手,我试图将多个以字符串作为键的映射合并,并将列表作为值来生成新的Map。
public class Student {
private String name;
private String country;
//Setters and Getters
}
现在,我有了一个以国家为基础将学生列入名单的实用班。
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", "India"));
MapAdder.addToMap("USA", 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
));
}
但是当我试图合并这两个地图时,我得到的是空地图。实际上,我需要一个包含三个键(印度、英国、美国)的地图,它们的值是从多个要合并的w.r.t键中列出的。
发布于 2020-12-23 09:19:39
首先,从代码中删除以下调用:
MapAdder.clearStudentMap();
您正在清除studentMap1
和studentMap2
。
当你这样做时:
studentMap1 = MapAdder.getStudentMap();
您将获得存储学生Map
的内存引用。当您在地图上调用clear
方法时
studentMap.clear();
您将清除存储在同一内存引用上的所有Map
条目。换句话说,以下声明
studentMap1 = MapAdder.getStudentMap();
不创建学生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值添加到左键的列表中。
顺便提一下,这些帮助方法中的一些--它们混淆了代码,并通过传递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, "India", new Student("Ram", "India"));
MapAdder.addToMap(studentMap1, "USA", new Student("Ronon", "USA"));
MapAdder.addToMap(studentMap1, "UK", new Student("Tony", "UK"));
MapAdder.addToMap(studentMap2, "India", new Student("Rivar", "India"));
MapAdder.addToMap(studentMap2, "UK", new Student("Loki", "UK"));
MapAdder.addToMap(studentMap2, "UK", new Student("Imran", "UK"));
MapAdder.addToMap(studentMap2, "USA", new Student("ryan", "USA"));
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; }
));
}
}
发布于 2020-12-23 19:04:04
主要问题是您一直在清除共享列表。需要建立独立的名单。
但是,有一种添加值的方法比使用MapAdder
类容易得多。记住,country
也是学生班级的一部分。因此,只要提取它,并创建地图使用流。
现在创建studentMap1
List<Student> list1 = List.of(
new Student("Mounish", "India"),
new Student("Zen", "USA"),
new Student("Ram", "India"),
new Student("Ronon", "USA"),
new Student("Tony", "UK"));
Map<String, List<Student>> studentMap1 =
list1.stream().collect(Collectors.groupingBy(Student::getCountry));
studentMap1.entrySet().forEach(System.out::println);
版画
USA=[{Zen, USA}, {Ronon, USA}]
UK=[{Tony, UK}]
India=[{Mounish, India}, {Ram, India}]
现在创建studentMap2
List<Student> list2 = List.of(
new Student("Rivar", "India"),
new Student("Loki", "UK"),
new Student("Imran", "UK"),
new Student("ryan", "USA"));
Map<String, List<Student>> studentMap2 =
list2.stream().collect(Collectors.groupingBy(Student::getCountry));
studentMap2.entrySet().forEach(System.out::println);
打印
USA=[{ryan, USA}]
UK=[{Loki, UK}, {Imran, UK}]
India=[{Rivar, India}]
现在您已经拥有了映射,您可以以相同的方式创建组合映射。只需使用每个地图的值,然后流他们得到学生的实例。
Map<String, List<Student>> map3 = Stream.of(studentMap1,studentMap2)
.map(Map::values) // values which is a collection of lists
.flatMap(Collection::stream) // flat map the two collections
.flatMap(Collection::stream) // flat map the lists to just
// a stream of students
.collect(Collectors.groupingBy(Student::getCountry));
map3.entrySet().forEach(System.out::println);
打印
USA=[{Zen, USA}, {Ronon, USA}, {ryan, USA}]
UK=[{Tony, UK}, {Loki, UK}, {Imran, UK}]
India=[{Mounish, India}, {Ram, India}, {Rivar, India}]
幸运的是,Map键作为学生类的一部分包含在其中。但让我们假设密钥独立于类之外。然后,您可以使用您的mapAdder
构建原始地图。最后的映射可以使用下面的merge
函数创建,用于合并重复的键。
Map<String, List<Student>> map4 =
Stream.of(studentMap1, studentMap2)
.flatMap(m -> m.entrySet().stream())
.collect(Collectors.toMap(Entry::getKey,
e -> new ArrayList<>(e.getValue),
(lst1, lst2) -> {lst1.addAll(lst2); return lst1;}));
带有getter、setter和toString的学生类
class Student {
private String name;
private String country;
public Student(String name, String country) {
this.name = name;
this.country = country;
}
public String getName() {
return name;
}
public String getCountry() {
return country;
}
@Override
public String toString() {
return String.format("{%s, %s}", name, country);
}
}
https://stackoverflow.com/questions/65428163
复制相似问题