我有两张地图:
Map<String, Object> map1;
Map<String, Object> map2;
我需要接收这些地图之间的差异。是否存在可能是 apache utils 如何接收这种差异?现在似乎需要获取每个映射的条目集并找到 diff1 = set1 - set2 和 diff2 = set2- set1。create summary map =diff1 + diff2 后看起来很别扭。是否存在另一种方式?谢谢。
我有两张地图:
Map<String, Object> map1;
Map<String, Object> map2;
我需要接收这些地图之间的差异。是否存在可能是 apache utils 如何接收这种差异?现在似乎需要获取每个映射的条目集并找到 diff1 = set1 - set2 和 diff2 = set2- set1。create summary map =diff1 + diff2 后看起来很别扭。是否存在另一种方式?谢谢。
谷歌番石榴怎么样?:
Maps.difference(map1,map2)
这是一个简单的片段,您可以使用它来代替大量的 Guava 库:
public static <K, V> Map<K, V> mapDifference(Map<? extends K, ? extends V> left, Map<? extends K, ? extends V> right) {
Map<K, V> difference = new HashMap<>();
difference.putAll(left);
difference.putAll(right);
difference.entrySet().removeAll(right.entrySet());
return difference;
}
如果我理解得很好,您正在尝试计算两个地图条目集之间的对称差异。
Map<String, Object> map1;
Map<String, Object> map2;
Set<Entry<String, Object>> diff12 = new HashSet<Entry<String, Object>>(map1.entrySet());
Set<Entry<String, Object>> diff21 = new HashSet<Entry<String, Object>>(map2.entrySet());
Set<Entry<String, Object>> result;
diff12.removeAll(map2.entrySet());
diff21.removeAll(map1.entrySet());
diff12.addAll(diff21);
考虑到你提到的尴尬行为,让我们仔细看看上面的代码行为。例如,如果我们从上面给出的链接中获取数字示例:
Map<String, Object> map1 = new HashMap<String, Object>();
map1.put("a", 1);
map1.put("b", 2);
map1.put("c", 3);
map1.put("d", 4);
Map<String, Object> map2 = new HashMap<String, Object>();
map2.put("a", 1);
map2.put("d", 4);
map2.put("e", 5);
如图所示计算差异后,输出:
System.out.println(Arrays.deepToString(diff12.toArray()));
给出:
[e=5, c=3, b=2]
这是正确的结果。但是,如果我们这样做:
public class CustomInteger {
public int val;
public CustomInteger(int val) {
this.val = val;
}
@Override
public String toString() {
return String.valueOf(val);
}
}
map1.put("a", new CustomInteger(1));
map1.put("b", new CustomInteger(2));
map1.put("c", new CustomInteger(3));
map1.put("d", new CustomInteger(4));
map2.put("a", new CustomInteger(1));
map2.put("d", new CustomInteger(4));
map2.put("e", new CustomInteger(5));
相同的算法给出以下输出:
[e=5, a=1, d=4, d=4, b=2, a=1, c=3]
这是不正确的(可能会被描述为尴尬:))
在第一个示例中,地图填充了 int 值,这些值会自动装箱为 Integer 值。
Integer 类有自己的equals和hashCode方法实现。
CustomInteger 类没有实现这些方法,因此它从无所不在的Object 类中继承它们。
Set 接口中removeAll 方法的API 文档说明如下:
从此集合中删除指定集合中包含的所有元素(可选操作)。如果指定的集合也是一个集合,这个操作有效地修改了这个集合,使得它的值是两个集合的不对称集合差。
为了确定两个集合中包含哪些元素,removeAll 方法使用集合元素的 equals 方法。
这就是问题所在:如果两个数值相同,整数的 equals 方法返回 true,而 Object 的 equals 方法仅在它是同一个对象时才返回 true,例如:
Integer a = 1; //autoboxing
Integer b = new Integer(1);
Integer c = 2;
a.equals(b); // true
a.equals(c); // false
CustomInteger d = new CustomInteger(1);
CustomInteger e = new CustomInteger(1);
CustomInteger f = new CustomInteger(2);
d.equals(e); //false
d.equals(f) // false
d.val == e.val //true
d.val == f.val //false
如果它仍然有点模糊,我强烈建议阅读以下教程:
Set<Entry<String, Object>> diff = new HashSet<Entry<String, Object>>((map1.entrySet()));
diff.addAll(map2.entrySet());//Union
Set<Entry<String, Object>> tmp = new HashSet<Entry<String, Object>>((map1.entrySet()));
tmp.retainAll(map2.entrySet());//Intersection
diff.removeAll(tmp);//Diff
基于Vlad 的示例来处理不同大小的地图
public static <K, V> Map<K, V> mapDiff(Map<? extends K, ? extends V> left, Map<? extends K, ? extends V> right) {
Map<K, V> difference = new HashMap<>();
difference.putAll(left);
difference.putAll(right);
difference.entrySet().removeAll(left.size() <= right.size() ? left.entrySet() : right.entrySet());
return difference;
}
尝试使用番石榴的MapDifference。
简单的方法来做到这一点。如果你想要复杂的方式,你可以改变过滤器来比较值。
Map<String, Object> map1 = new HashMap<String, Object>() {{
put("A", "1");
put("B", "2");
put("C", "3");
}};
Map<String, Object> map2 = new HashMap<String, Object>() {{
put("A", "1");
put("B", "2");
put("D", "3");
}};
Map<String, Object> newList = map1.keySet().stream().filter(str -> !map2.containsKey(str)).collect(Collectors.toMap(v -> v, v -> map1.get(v)));
Map<String, Object> oldList = map2.keySet().stream().filter(str -> !map1.containsKey(str)).collect(Collectors.toMap(v -> v, v -> map2.get(v)));
System.out.println(newList);
System.out.println(oldList);