Изучите различные способы сравнения двух хэш-карт в Java по ключам, значениям и парам ключ-значение. Также научитесь сравнивать карты, разрешая или ограничивая дублирующиеся значения.
1. Сравните карты для одинаковых ключей и значений
1.1 Использование Map.equals()
По умолчанию метод HashMap.equals() сравнивает два хэш-файла по парам ключ-значение. Это означает, что оба экземпляра HashMap должны иметь абсолютно одинаковые пары ключ-значение и оба должны быть одинакового размера. Порядок пар ключ-значение может быть разным и не играет роли при сравнении.
Map<String, Integer> map1 = Map.of("A", 1, "B", 2);Map<String, Integer> map2 = Map.of("A", 1, "B", 2);Map<String, Integer> map3 = Map.of("C", 1, "D", 2);Assertions.assertTrue( map1.equals(map2) );Assertions.assertFalse( map1.equals(map3) );
1.2 Сравнение карт со значениями типа массива
Стоит отметить, что ключи и значения Map сравниваются с использованием их метода equals(), поэтому объекты key и value должны правильно реализовать метод equals(), чтобы дать согласованный результат. Например, если значение Map является массивом, то сравнение не будет работать, так как array.equals() сравнивает идентификатор объекта, а не содержимое массива.
Map<String, Integer[]> map4 = Map.of("A", new Integer[]{1}, "B", new Integer[]{2});Map<String, Integer[]> map5 = Map.of("A", new Integer[]{1}, "B", new Integer[]{2});Assertions.assertFalse(map4.equals(map5));
В таком случае мы можем создать собственный метод для сравнения содержимого массива с помощью метода Arrays.equals().
private static boolean checkEqualMapsWithArrayTypeValues(Map<String, Integer[]> firstMap,Map<String, Integer[]> secondMap) {if(firstMap.size() != secondMap.size())return false;return firstMap.entrySet().stream().allMatch(e -> Arrays.equals(e.getValue(), secondMap.get(e.getKey())));}
Теперь сравнение карт проверит содержимое массива и выдаст правильный результат.
Map<String, Integer[]> map4 = Map.of("A", new Integer[]{1}, "B", new Integer[]{2});Map<String, Integer[]> map5 = Map.of("A", new Integer[]{1}, "B", new Integer[]{2});Assertions.assertFalse( checkEqualMapsWithArrayTypeValues(map4, map5) );
2. Сравнение ключей карты
Мы можем сравнить две Карты, чтобы определить, есть ли у них одинаковые ключи или нет. Или мы можем найти недостающие ключи во второй Карте, если это необходимо.
2.1. Обе карты имеют одинаковые ключи
Если мы хотим сравнить хэш-карты по ключам, то есть две хэш-карты будут равны, если у них одинаковый набор ключей, мы можем использовать функцию HashMap.keySet(). Она возвращает все ключи карты в HashSet.
Затем мы можем сравнить HashSet для обеих карт с помощью метода Set.equals(). Он возвращает true, если два набора имеют одинаковый размер, и каждый элемент указанного набора содержится в другом наборе.
Map<String, Integer> map1 = Map.of("A", 1, "B", 2);Map<String, Integer> map2 = Map.of("A", 1, "B", 2);Assertions.assertTrue( map1.keySet().equals(map2.keySet()) );Map<String, Integer> map3 = Map.of("A", 1, "B", 2, "C", 3, "D", 4);Assertions.assertFalse( map1.keySet().equals(map6.keySet()) );
2.2. Разница в ключах карты
Нам может быть интересно узнать, какие дополнительные ключи есть у первой хэш-карты по сравнению со второй. Чтобы получить эту разницу, выполните объединение ключей из обеих хэш-карт, а затем удалите все ключи, присутствующие в первой хэш-карте.
Программа на Java для поиска разницы между двумя хэш-картами.
HashSet<String> unionKeys = new HashSet<>(map1.keySet());unionKeys.addAll(map3.keySet());unionKeys.removeAll(map1.keySet());Assertions.assertEquals(Set.of("C", "D"), unionKeys );
2. Сравнение значений карты
Если мы хотим сравнить хэш-карты по значениям, то есть две хэш-карты будут равны, если они имеют абсолютно одинаковый набор значений. Обратите внимание, что HashMap допускает дублирующиеся значения, поэтому решите, хотите ли вы сравнивать хэш-карты с дубликатами или без дублирующихся значений.
3.1. Допускаются повторяющиеся значения.
Добавьте все значения из HashMap.values() в ArrayList для обеих карт. Теперь сравните оба списка массивов на предмет эквивалентности.
new ArrayList<>( map1.values() ).equals(new ArrayList<>( map2.values() )); //truenew ArrayList<>( map1.values() ).equals(new ArrayList<>( map3.values() )); //false
3.2. Повторяющиеся значения НЕ допускаются.
Если вы хотите удалить повторяющиеся значения перед сравнением хэш-карт, добавьте все значения в HashSet, который автоматически игнорирует повторяющиеся значения.
new HashSet<>( map1.values() ).equals(new HashSet<>( map2.values() )); //truenew HashSet<>( map1.values() ).equals(new HashSet<>( map3.values() )); //true
4. Разница в карте с гуавой
Если нам интересно найти разницу между двумя картами, то Guava предоставляет отличный API Maps.difference().
<dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>31.1-jre</version></dependency>
Map.difference() возвращает экземпляр класса MapDifference. Проверяя MapDifference, мы можем найти разницу в Maps несколькими способами.
MapDifference diff = Maps.difference(map1, map2);
Давайте посмотрим на API в действии на простом примере. У map1 и map2 есть некоторые общие записи, и у каждой карты есть несколько различных записей.
Map<String, Integer> map1 = Map.of("A", 1, "B", 2, "E", 5, "F", 6);Map<String, Integer> map2 = Map.of("A", 1, "B", 2, "C", 3, "D", 4);MapDifference<String, Integer> diff = Maps.difference(map1, map2);Assertions.assertFalse(diff.areEqual());Assertions.assertEquals(Map.of("A", 1, "B", 2), diff.entriesInCommon());Assertions.assertEquals(Map.of("E", 5, "F", 6), diff.entriesOnlyOnLeft());Assertions.assertEquals(Map.of("C", 3, "D", 4), diff.entriesOnlyOnRight());
5. Заключение
В этом коротком уроке мы научились сравнивать две карты на предмет равенства их записей, ключей и значений. Мы также научились находить различия в картах с помощью простых API Java, а также API MapDifference от Guava.
Напишите мне ваши вопросы, связанные со сравнением хэш-карт в Java.