Как получить разницу в картах в java?

У меня есть две карты:

Map<String, Object> map1;
Map<String, Object> map2;

Мне нужно получить разницу между этими картами. Существует ли может быть apache utils, как получить эту разницу? На данный момент, кажется, нужно взять набор записей каждой карты и найти diff1 = set1 - set2 и diff2 = set2 - set1. После создания сводной карты = diff1 + diff2 Это выглядит очень неловко. Существует ли другой способ? Спасибо.

Ответы

Ответ 1

Как насчет google guava?:

Maps.difference(map1,map2)

Ответ 2

Вот простой фрагмент, который вы можете использовать вместо массивной библиотеки 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;
}

Посмотрите весь рабочий пример

Ответ 3

Если я хорошо понял, вы пытаетесь вычислить симметричную разницу между двумя наборами записей карт.

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 не реализует эти методы, поэтому наследует их от вездесущего Класс объекта.

API doc для метода removeAll из Установить интерфейс говорит следующее:

Удаляет из этого множества все его элементы, которые содержатся в указанной коллекции (дополнительная операция). Если указанная коллекция также является набором, эта операция эффективно модифицирует этот набор, так что его значение представляет собой асимметричную разность наборов двух наборов.

Чтобы определить, какие элементы содержатся в обеих коллекциях, метод removeAll использует метод equals для элемента коллекции.

И что метод catch: Integer equals возвращает true, если два числовых значения одинаковы, а метод 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

Если он все еще немного нечеткий, я настоятельно рекомендую прочитать следующие уроки:

Ответ 4

    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

Ответ 5

Существует MapDifference API Google Collections Library, который предоставляет методы вроде:

 boolean    areEqual() 

Возвращает true, если между двумя картами нет различий; то есть, если карты равны.

 Map<K,MapDifference.ValueDifference<V>>    entriesDiffering() 

Возвращает немодифицируемую карту, описывающую ключи, которые отображаются на обеих картах, но с разными значениями.

 Map<K,V>   entriesInCommon() 

Возвращает немодифицируемую карту, содержащую записи, которые отображаются на обеих картах; т.е. пересечение двух отображений.

Ответ 6

Основываясь на примере Влада для работы с картами разных размеров

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;
    }

Ответ 7

Попробуйте использовать guava MapDifference.