Как сравнить две карты их значениями

Как сравнить две карты их значениями? Я имею две карты, содержащие равные значения, и хочу сравнить их их значениями. Вот пример:

    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

Как я должен изменить код для получения истинного?

12
задан rajah9 24 July 2019 в 11:47
поделиться

7 ответов

Ваши попытки построить разные строки с помощью конкатенации потерпят неудачу, поскольку она выполняется во время компиляции. Обе эти карты имеют одну пару; каждая пара будет иметь «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"} на быть равными ... в конце концов, наборы значений равны.

Если бы вы могли дать более строгое определение того, что вы хотите, было бы легче убедиться, что мы даем вам правильный ответ.

8
ответ дан 2 December 2019 в 03:02
поделиться

Чтобы проверить, имеют ли две карты одинаковые значения, вы можете сделать следующее:

  • Получить их Коллекцию 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())

См. Также:

6
ответ дан 2 December 2019 в 03:02
поделиться

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

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

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

1
ответ дан 2 December 2019 в 03:02
поделиться

Правильный способ сравнения карт на предмет равенства значений:

  1. Убедитесь, что карты одинакового размера (!)
  2. Получите набор ключей из одной карты
  3. Для каждого ключа из этого набора, который вы получили, проверьте, что значение, полученное из каждой карты для этот ключ тот же (если ключ отсутствует на одной карте, это полное нарушение равенства)

Другими словами (минус обработка ошибок):

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;
}
35
ответ дан 2 December 2019 в 03:02
поделиться

Поскольку вы спрашивали о готовых API ... ну, общее достояние Apache. В библиотеке коллекций есть класс CollectionUtils , который предоставляет простые в использовании методы для работы с коллекциями / проверки, такие как пересечение, различие и объединение.

2
ответ дан 2 December 2019 в 03:02
поделиться

Результат равенства в вашем примере, очевидно, неверен, потому что вы сравниваете карту 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));

Объединение ваших строк не имеет никакого эффекта, потому что оно будет выполнено во время компиляции.

0
ответ дан 2 December 2019 в 03:02
поделиться

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

Например, если вы сравните две хэш-карты в java: - вы можете просто сравнить одинаковые пары "ключ-значение" - вы также можете захотеть для сравнения, если ключи упорядочены одинаково - Вы также можете сравнить, одинакова ли оставшаяся емкость ... Вы можете сравнивать многие вещи!

Что будет делать такой инструмент при сравнении двух различных реализаций карт, таких как: - одна карта допускает нулевые ключи - другая генерирует исключение времени выполнения на map2.get (null)

Вам лучше реализовать собственное решение в соответствии с тем, что вам действительно нужно, и я думаю, что вы уже получили некоторые ответы выше :)

1
ответ дан 2 December 2019 в 03:02
поделиться
Другие вопросы по тегам:

Похожие вопросы: