java - 根据条件合并映射

标签 java java-8 java-stream

我有一个名为 Person 的类:

class Person {
    private String id;
    private String name;
}

现在我有两张 map

final Map<Integer, List<Person>> map1 = ImmutableMap.of(1, ImmutableList.of(
                new Person("id1", "name1"),
                new Person("id2", "name2")),
                2, ImmutableList.of(
                        new Person("id3", "name3"),
                        new Person("id4", "name4")));

final Map<Integer, List<Person>> map2 = ImmutableMap.of(2, ImmutableList.of(
                    new Person("id1", "name5")));

现在我想根据以下内容合并这些:

  1. 如果map2包含map1中不存在的键,只需将该键与map1中的值一起添加
  2. 如果map2包含map1中存在的key,检查map1中的Person是否存在具有相同id的人,如果是这种情况,则更新该人,如果不存在具有相同id的人,则将新人添加到列表。

上述情况的结果是

1 -> Person("id1", "name5"), Person("id2", "name2")
2 -> Person("id3", "name3"), Person("id4", "name4")

我可以使用原始的方式来做到这一点,但它很大,我正在尝试为此提出一个干净的基于 java 8 流的解决方案。

如有任何帮助,我们将不胜感激。

final HashMap<Integer, List<Person>> map1 = new HashMap<Integer, List<Person>>() {{
    put(1, Arrays.asList(
            new Person("id1", "name1"),
            new Person("id2", "name2")));
    put(2, Arrays.asList(
            new Person("id3", "name3"),
            new Person("id4", "name4")));
}};

final HashMap<Integer, List<Person>> map2 = new HashMap<Integer, List<Person>>() {{
    put(1, Arrays.asList(
            new Person("id1", "name5")));
}};

final Map<Integer, List<Person>> collect = Stream.of(map1, map2).flatMap(map -> map.entrySet().stream())
        .collect(Collectors.toMap(
                Map.Entry::getKey,
                Map.Entry::getValue, (v1, v2) -> {
                    List<Person> h = new ArrayList<>();
                    h.addAll(v1);
                    v2.forEach(x -> {
                        v1.forEach(y -> {
                            if(x.getId().equals(y.getId())) {
                                h.remove(y);
                            }
                        });
                    });
                    h.addAll(v2);
                    return h;
                }
        ));

System.out.println(collect);

最佳答案

为了更好的可读性,您可能需要一些抽象:

Map<Integer, List<Person>> collect =
        Stream.concat(map1.entrySet().stream(), map2.entrySet().stream())
                .collect(Collectors.toMap(Map.Entry::getKey,
                        Map.Entry::getValue, this::mergeFunc));

public List<Person> mergeFunc(List<Person> peopleOne, List<Person> peopleTwo) {
    List<Person> mergedPeople = new ArrayList<>(peopleOne);
    mergedPeople.removeIf(y -> peopleTwo.stream().anyMatch(p -> y.getId().equals(p.getId())));
    mergedPeople.addAll(peopleTwo);
    return mergedPeople;
}

关于java - 根据条件合并映射,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60537633/

相关文章:

java - 使用 Java 流打印从 A 到 Z 的字母

java - CompletableFuture 从内部注入(inject)

java - 使用java 8流转换为大写字母

java - 如何表示一个空的 InputStream

java - 如何在java 8中使用收集器和流自动递增 HashMap 的键

JAVA HOME 设置为 1.8 但 eclipse 使用 java 9

java - 获取 JCheckListBox 的所有选中项索引

java - 带表单生成器的 JTree

java - Java 8 中流和闭包的成本

java - 装饰器模式 - 如何同时装饰两种类型