微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何将多个地图与多个相同的键和列表组合为值?

如何解决如何将多个地图与多个相同的键和列表组合为值?

我是 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();

您正在清除 studentMap1studentMap2

当你这样做时:

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 实例时,您可以覆盖其 putputAll 方法,这样它们就不会替换现有值,而是附加它们,即合并值列表相同的键:

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 举报,一经查实,本站将立刻删除。