Reputation: 58772
I need to find only differences between 2 maps, while the different can be by missing key or by different value for key.
I find a general answer for Differences between maps
sources.removeAll(targets) ... leaves only entries in sources that are only in sources, not in target
whereas
sources.retainAll(targets) ... leaves only entries that are in both sets
But I'm not sure it's better than the following code, because I need to check apart from key existence also that the values are different
Map<K, V> updatedMap = new EnumMap<>(K.class);
for (Map.Entry<K, V> finalSet : secondMap.entrySet()) {
K currentKey = finalSet.getKey();
if (!firstMap.containsKey(currentKey) || firstMap.get(currentKey) != finalSet.getValue()) {
updatedMap.put(currentKey, finalSet.getValue());
firstMap.remove(currentKey);
}
}
for (Map.Entry<K, V> currentSet : firstMap.entrySet()) {
K currentKey = currentSet.getKey();
if (!secondMap.containsKey(currentKey)) {
updatedMap.put(currentKey, currentSet.getValue());
} else if (secondMap.get(currentKey) != currentSet.getValue()) {
updatedMap.put(currentKey, secondMap.get(currentKey));
}
}
Is their a better way of finding the differences between maps including values?
Upvotes: 4
Views: 1502
Reputation: 35427
Maps.difference(Map, Map)
.Their wiki explains how it works, but you can find below the solution to your problem.
Map<String, Integer> left = ImmutableMap.of("a", 1, "b", 2, "c", 3);
Map<String, Integer> right = ImmutableMap.of("b", 2, "c", 4, "d", 5);
MapDifference<String, Integer> diff = Maps.difference(left, right);
Map<String, Integer> output = new HashMap<>();
output.putAll(diff.entriesOnlyOnLeft());
output.putAll(diff.entriesOnlyOnRight());
for (Map.Entry<String,MapDifference.ValueDifference<Integer>> e: diff.entriesDiffering().entrySet()) {
// Java 10 and later : for (var e: diff.entriesDiffering().entrySet())
output.put(e.getKey(), e.getValue().rightValue());
}
System.out.println(output); // {a=1, c=4, d=5}
Upvotes: 1
Reputation: 120858
Well, you could compare Entry
s from a Map
, because that class overrides equals/hashCode
in the manner that you want. It's not entirely clear which entries you would want to keep, the ones from the left map or the right map or any of them.
For example this could be done via :
Map<Integer, String> allDifs =
Sets.symmetricDifference(left.entrySet(), right.entrySet())
.stream()
.collect(Collectors.toMap(Entry::getKey, Entry::getValue));
On the other hand if you just want to keep entries form the second (right) Map
:
Map<Integer, String> result =
Sets.difference(right.entrySet(), left.entrySet())
.stream()
.collect(Collectors.toMap(Entry::getKey, Entry::getValue));
System.out.println(result);
Obviously you need guava
and java-8
for this...
EDIT
what you actually want is not achievable with Collectors.toMap
, but you can do it with:
Map<Integer, String> result = new HashMap<>();
Sets.symmetricDifference(right.entrySet(), left.entrySet())
.stream()
.forEachOrdered(x -> {
String previousValue = result.putIfAbsent(x.getKey(), x.getValue());
if (previousValue != null) {
result.replace(x.getKey(), right.get(x.getKey()));
}
});
Upvotes: 3