Reputation: 3720
Lets say I have a method with a following signature:
Map<String, String> merge (String[][] ... maps)
It takes a (variadic) number of two-dim arrays which represent mappings, for example:
String[][] m1 = new String[][] {
{"k1", "a"},
{"k2", "b"}
};
String[][] m2 = new String[][] {
{"k1", "a"},
{"k2", "b"},
{"k3", "c"}
};
String[][] m3 = new String[][] {
{"k1", "x"},
{"k2", "b"}
};
Now I can merge any two of the maps left-to-right like this:
Map<String, String> m1 = Stream.of(map1).collect(Collectors.toMap(k -> k[0], v -> v[1]));
Map<String, String> m2 = Stream.of(map2).collect(Collectors.toMap(k -> k[0], v -> Optional.ofNullable(v[1]).orElse("null")));
m1.forEach((key, value) -> m2.merge(key, value, (v1, v2) -> v1));
But how can I go about merging a variadic number of such array-maps, so that after passing m1, m2, m3
as defined above the result is:
String[][] m3 = new String[][] {
{"k1", "x"},
{"k2", "b"}
{"k3", "c"}
};
Upvotes: 2
Views: 99
Reputation: 50756
It's quite simple, if I'm understanding your question correctly. You just flatMap all the entries and collect to map, with a merge function that selects the later value:
Map<String, String> merge (String[][] ... maps) {
return Arrays.stream(maps)
.flatMap(Arrays::stream)
.collect(Collectors.toMap(a -> a[0], a -> a[1], (a, b) -> b));
}
If you want to convert it back to an array, you can do
String[][] m3 = merge(maps)
.entrySet()
.stream()
.map(e -> new String[] { e.getKey(), e.getValue() })
.toArray(String[][]::new);
Upvotes: 6
Reputation: 7917
Map<String, String> merge(String[][]... maps) {
return Stream.of(maps)
.flatMap(Arrays::stream) //flatten all maps into a single stream
.map(s -> Map.entry(s[0], s[1])) //convert array to Entry
.collect(Collectors.toMap(Map.Entry::getKey,
Map.Entry::getValue,
(o1, o2) -> o2));
}
Edit: No need to convert to Entry. We can directly collect to map as @shmosel showed.
Upvotes: 3