如何在java中获取地图的差异?
我有两张地图:
Map map1; Map map2;
我需要收到这些地图之间的差异。 是否存在可能是apache utils如何获得这种差异? 现在似乎需要获取每个地图的入口集,发现diff1 = set1 – set2和diff2 = set2- set1。 创建汇总map = diff1 + diff2之后看起来非常笨拙。 是否存在另一种方式? 谢谢。
谷歌番石榴怎么样?:
Maps.difference(map1,map2)
这是一个简单的代码片段,您可以使用它而不是大量的Guava库:
public static Map mapDifference(Map extends K, ? extends V> left, Map extends K, ? extends V> right) { Map difference = new HashMap<>(); difference.putAll(left); difference.putAll(right); difference.entrySet().removeAll(right.entrySet()); return difference; }
查看整个工作示例
如果我理解得很好,你试图计算两个地图入口集之间的对称差异 。
Map map1; Map map2; Set> diff12 = new HashSet>(map1.entrySet()); Set> diff21 = new HashSet>(map2.entrySet()); Set> result; diff12.removeAll(map2.entrySet()); diff21.removeAll(map1.entrySet()); diff12.addAll(diff21);
考虑到你提到的尴尬行为,让我们仔细看看上面的代码行为。 例如,如果我们从上面给出的链接中获取数值示例:
Map map1 = new HashMap(); map1.put("a", 1); map1.put("b", 2); map1.put("c", 3); map1.put("d", 4); Map map2 = new HashMap(); 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类 inheritance它们。
Set接口中 removeAll方法的API文档说明如下:
从此集合中删除指定集合中包含的所有元素(可选操作)。 如果指定的集合也是一个集合,则此操作会有效地修改此集合,以使其值为两个集合的不对称集合差异。
为了确定两个集合中包含哪些元素,removeAll方法使用集合元素的equals方法。
这就是问题:如果两个数值相同,则Integer的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
如果它仍然有点模糊,我强烈建议阅读以下教程:
- 学习Java语言
- 集合
Set> diff = new HashSet>((map1.entrySet())); diff.addAll(map2.entrySet());//Union Set> tmp = new HashSet>((map1.entrySet())); tmp.retainAll(map2.entrySet());//Intersection diff.removeAll(tmp);//Diff
Google Collections Library
了一个MapDifference API,它公开了以下方法:
boolean areEqual()
如果两个映射之间没有差异,则返回true; 也就是说,如果地图相同。
Map> entriesDiffering()
返回一个不可修改的映射,描述出现在两个映射中但具有不同值的键。
Map entriesInCommon()
返回包含两个映射中显示的条目的不可修改的映射; 也就是两张地图的交点。
以弗拉德的例子为基础,使用不同大小的地图
public static Map mapDiff(Map extends K, ? extends V> left, Map extends K, ? extends V> right) { Map difference = new HashMap<>(); difference.putAll(left); difference.putAll(right); difference.entrySet().removeAll(left.size() <= right.size() ? left.entrySet() : right.entrySet()); return difference; }
尝试使用guava的MapDifference 。