简体   繁体   中英

Merge Map based on a condition

I have a class called Person :

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

Now I have two maps

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")));

Now I would like to merge these based on following:

  1. If map2 contains a key not present in map1, just add that key along with values in map1
  2. if map2 contains a key present in map1, check if the Person in map1 exists with same id, if that is the case, update the person, if no no person exists with the same id, just add the new person to the list.

Result for the case above would be

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

I am able to do it using the primitive way, but its a but large, I am trying to come up with a clean java 8 stream based solution for this.

Any help would be appreciated.

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);

You might want some abstraction there possibly for better readability:

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;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM