Как сравнить две карты их значениями? Я имею две карты, содержащие равные значения, и хочу сравнить их их значениями. Вот пример:
Map a = new HashMap();
a.put("foo", "bar"+"bar");
a.put("zoo", "bar"+"bar");
Map b = new HashMap();
b.put(new String("foo"), "bar"+"bar");
b.put(new String("zoo"), "bar"+"bar");
System.out.println("equals: " + a.equals(b)); // obviously false
Как я должен изменить код для получения истинного?
Ваши попытки построить разные строки с помощью конкатенации потерпят неудачу, поскольку она выполняется во время компиляции. Обе эти карты имеют одну пару; каждая пара будет иметь «foo» и «barbar» в качестве ключа / значения, причем обе будут использовать одну и ту же строковую ссылку.
Предполагая, что вы действительно хотите сравнить наборы значений без какой-либо ссылки на ключи, это просто случай:
Set<String> values1 = new HashSet<>(map1.values());
Set<String> values2 = new HashSet<>(map2.values());
boolean equal = values1.equals(values2);
Возможно , что сравнение map1.values ()
с map2.values ()
будет работать, но также возможно, что порядок, в котором они возвращаются, будет использоваться при сравнении равенства, а это не то, что вам нужно.
Обратите внимание, что использование набора имеет свои собственные проблемы - потому что приведенный выше код будет считать карту {"a": "0", "b": "0"} и {"c": "0"} на быть равными ... в конце концов, наборы значений равны.
Если бы вы могли дать более строгое определение того, что вы хотите, было бы легче убедиться, что мы даем вам правильный ответ.
Чтобы проверить, имеют ли две карты одинаковые значения, вы можете сделать следующее:
Коллекцию values ()
views List
Collections.sort
те списки равными
Что-то вроде этого работает (хотя его границы типов могут быть улучшены):
static <V extends Comparable<V>>
boolean valuesEquals(Map<?,V> map1, Map<?,V> map2) {
List<V> values1 = new ArrayList<V>(map1.values());
List<V> values2 = new ArrayList<V>(map2.values());
Collections.sort(values1);
Collections.sort(values2);
return values1.equals(values2);
}
Тестовая оснастка:
Map<String, String> map1 = new HashMap<String,String>();
map1.put("A", "B");
map1.put("C", "D");
Map<String, String> map2 = new HashMap<String,String>();
map2.put("A", "D");
map2.put("C", "B");
System.out.println(valuesEquals(map1, map2)); // prints "true"
Это O (N log N)
из-за Collections.sort
.
Проверить, равны ли ключи , проще, потому что они Set
:
map1.keySet().equals(map2.keySet())
Если вы предполагаете, что могут быть повторяющиеся значения, единственный способ сделать это - поместить значения в списки, отсортировать их и сравнить списки, а именно:
List<String> values1 = new ArrayList<String>(map1.values());
List<String> values2 = new ArrayList<String>(map2.values());
Collections.sort(values1);
Collections.sort(values2);
boolean mapsHaveEqualValues = values1.equals(values2);
Если значения не могут содержать повторяющиеся значения, то вы можете выполнить описанное выше без сортировки с использованием наборов.
Правильный способ сравнения карт на предмет равенства значений:
Другими словами (минус обработка ошибок):
boolean equalMaps(Map<K,V>m1, Map<K,V>m2) {
if (m1.size() != m2.size())
return false;
for (K key: m1.keySet())
if (!m1.get(key).equals(m2.get(key)))
return false;
return true;
}
Поскольку вы спрашивали о готовых API ... ну, общее достояние Apache. В библиотеке коллекций есть класс CollectionUtils , который предоставляет простые в использовании методы для работы с коллекциями / проверки, такие как пересечение, различие и объединение.
Результат равенства в вашем примере, очевидно, неверен, потому что вы сравниваете карту a с некоторыми значениями в ней с пустой картой b (возможно, копией и ошибка вставки). Я рекомендую использовать правильные имена переменных (чтобы избежать подобных ошибок), а также использовать универсальные типы.
Map<String, String> first = new HashMap<String, String>();
first.put("f"+"oo", "bar"+"bar");
first.put("fo"+"o", "bar"+"bar");
Map second = new HashMap();
second.put("f"+"oo", "bar"+"bar");
second.put("fo"+"o", "bar"+"bar");
System.out.println("equals: " + first.equals(second));
Объединение ваших строк не имеет никакого эффекта, потому что оно будет выполнено во время компиляции.
Я не думаю, что существует инструмент, похожий на apache-common, для сравнения карт, поскольку равенство двух карт очень неоднозначно и зависит от потребности разработчика и реализация карты ...
Например, если вы сравните две хэш-карты в java: - вы можете просто сравнить одинаковые пары "ключ-значение" - вы также можете захотеть для сравнения, если ключи упорядочены одинаково - Вы также можете сравнить, одинакова ли оставшаяся емкость ... Вы можете сравнивать многие вещи!
Что будет делать такой инструмент при сравнении двух различных реализаций карт, таких как: - одна карта допускает нулевые ключи - другая генерирует исключение времени выполнения на map2.get (null)
Вам лучше реализовать собственное решение в соответствии с тем, что вам действительно нужно, и я думаю, что вы уже получили некоторые ответы выше :)