I am trying to merge multiple map with Java stream API. The reqiurements like ...
- this method can receive multiple map, does not care hot many of it
- support 2 merge method: intersection, union
- if key duplicates, it overwrites with later value
Here is basic code I wrote,
public class MapMergeHelper {
public static Map<String, String> merge (MapMergeOperation mergeOperation, Map<String, String> ... maps) {
Map<String, String> merged;
switch (mergeOperation) {
case INTERSECTION -> {
Set<Map.Entry<String, String>> entrySet = maps[0].entrySet();
for (int i = 1; i < maps.length; i++) {
final int current = i;
entrySet = entrySet.stream().filter(entry -> maps[current].containsKey(entry.getKey()))
.collect(Collectors.toSet());
}
merged = entrySet.stream()
.collect(Collectors.toMap(entry -> entry.getKey(), entry -> entry.getValue()));
}
default -> {
// UNION -> If key duplicates, then override
merged = Stream.of(maps)
.flatMap(entry -> entry.entrySet().stream())
.collect(Collectors.toMap(entry -> entry.getKey(), entry -> entry.getValue(), (o, o2) -> o2));
}
}
return merged;
}
}
MapMergeOperation
is simple Enum like this
public enum MapMergeOperation {
UNION,
INTERSECTION
}
And here is the testcase
public class MapMergeHelperTest {
@Test
public void testMerge() {
Map<String, String> testEntryMapA = Map.of("key1", "a", "key2", "b", "key3", "c", "key4", "d");
Map<String, String> testEntryMapB = Map.of("key1", "b");
Map<String, String> testEntryMapC = Map.of("key1", "a", "key5", "e");
{
// test intersection
Map<String, String> actual = MapMergeHelper.merge(MapMergeOperation.INTERSECTION, testEntryMapA, testEntryMapB, testEntryMapC);
assertThat(actual.keySet()).containsExactly("key1");
assertThat(actual.get("key1")).isEqualTo("a"); // override
}
{
// test union
Map<String, String> actual = MapMergeHelper.merge(MapMergeOperation.UNION, testEntryMapA, testEntryMapB, testEntryMapC);
assertThat(actual.keySet()).containsExactlyInAnyOrder("key1", "key2", "key3", "key4", "key5");
}
}
}
The problem is, I think it is not efficient enough because calling collect(Collections.toSet())
every time inside of for loop.
I am looking for a way to achieve goal in better readable, efficient way!
map[0].keySet().retainAll(map[i].keySet());
Loop in reverse order to retain the value in last map. \$\endgroup\$