use*_*818 18 java collections map set set-difference
我有两张地图:
Map<String, Object> map1;
Map<String, Object> map2;
Run Code Online (Sandbox Code Playgroud)
我需要收到这些地图之间的差异.是否存在可能是apache utils如何获得这种差异?现在似乎需要获取每个地图的入口集,并找到diff1 = set1 - set2和diff2 = set2- set1.创建汇总map = diff1 + diff2之后看起来非常笨拙.还存在另一种方式吗?谢谢.
Koe*_*err 38
如何谷歌番石榴?
Maps.difference(map1,map2)
Run Code Online (Sandbox Code Playgroud)
        Vla*_*iev 20
这是一个简单的代码片段,您可以使用它而不是大量的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;
}
Run Code Online (Sandbox Code Playgroud)
        如果我理解得很好,你试图计算两个地图入口集之间的对称差异.
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);
Run Code Online (Sandbox Code Playgroud)
考虑到你提到的尴尬行为,让我们仔细看看上面的代码行为.例如,如果我们从上面给出的链接中获取数值示例:
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);
Run Code Online (Sandbox Code Playgroud)
在计算出差异后,输出如下:
System.out.println(Arrays.deepToString(diff12.toArray()));
Run Code Online (Sandbox Code Playgroud)
得到:
[e=5, c=3, b=2]
Run Code Online (Sandbox Code Playgroud)
这是正确的结果.但是,如果我们这样做:
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));
Run Code Online (Sandbox Code Playgroud)
相同的算法给出以下输出:
[e=5, a=1, d=4, d=4, b=2, a=1, c=3]
Run Code Online (Sandbox Code Playgroud)
这是不正确的(可能被描述为尴尬:))
在第一个示例中,地图填充了int值,这些值将自动加框为Integer值.
Integer类有自己的equals和hashCode方法实现.
CustomInteger类不实现这些方法,因此它从无所不在的Object类继承它们.
对于该API文档RemoveAll方法从Set接口说以下内容:
从此集合中删除指定集合中包含的所有元素(可选操作).如果指定的集合也是一个集合,则此操作会有效地修改此集合,以使其值为两个集合的不对称集合差异.
为了确定两个集合中包含哪些元素,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
Run Code Online (Sandbox Code Playgroud)
如果它仍然有点模糊,我强烈建议阅读以下教程: