Как сравнить две карты по их значениям - PullRequest
12 голосов
/ 20 апреля 2010

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

    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

    .... what to call to obtain a true?

[[ РЕДАКТИРОВАТЬ: кто-то, пожалуйста, отредактируйте и исправьте этот вопрос, чтобы означать то, что он на самом деле должен означать. Код выше печатает «true», а не «false». ]]

Очевидно, что осуществить сравнение не сложно, достаточно сравнить все ключи и связанные с ними значения. Я не верю, что я первый, кто сделал это, поэтому уже должны быть библиотечные функции либо в java, либо в одной из библиотек jakarta.commons.

Спасибо

Ответы [ 12 ]

35 голосов
/ 20 апреля 2010

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

  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;
}
7 голосов
/ 20 апреля 2010

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

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

6 голосов
/ 20 апреля 2010

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

  • Получите их Collection<V> values() просмотров
  • Завернуть в List<V>
  • Collections.sort эти списки
  • Проверьте, являются ли два списка equals

Нечто подобное работает (хотя можно улучшить границы его типов):

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<K>:

map1.keySet().equals(map2.keySet())

Смотри также:

2 голосов
/ 04 июня 2015

Этот вопрос старый, но все еще актуален.

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

public static <K, V> boolean mapEquals(Map<K, V> leftMap, Map<K, V> rightMap) {
    if (leftMap == rightMap) return true;
    if (leftMap == null || rightMap == null || leftMap.size() != rightMap.size()) return false;
    for (K key : leftMap.keySet()) {
        V value1 = leftMap.get(key);
        V value2 = rightMap.get(key);
        if (value1 == null && value2 == null)
            continue;
        else if (value1 == null || value2 == null)
            return false;
        if (!value1.equals(value2))
            return false;
    }
    return true;
}
2 голосов
/ 12 апреля 2012

Все они возвращаются равными. Они на самом деле не делают сравнения, что полезно для сортировки. Это будет вести себя как компаратор:

private static final Comparator stringFallbackComparator = new Comparator() {
    public int compare(Object o1, Object o2) {
        if (!(o1 instanceof Comparable))
            o1 = o1.toString();
        if (!(o2 instanceof Comparable))
            o2 = o2.toString();
        return ((Comparable)o1).compareTo(o2);
    }
};

public int compare(Map m1, Map m2) {
    TreeSet s1 = new TreeSet(stringFallbackComparator); s1.addAll(m1.keySet());
    TreeSet s2 = new TreeSet(stringFallbackComparator); s2.addAll(m2.keySet());
    Iterator i1 = s1.iterator();
    Iterator i2 = s2.iterator();
    int i;
    while (i1.hasNext() && i2.hasNext())
    {
        Object k1 = i1.next();
        Object k2 = i2.next();
        if (0!=(i=stringFallbackComparator.compare(k1, k2)))
            return i;
        if (0!=(i=stringFallbackComparator.compare(m1.get(k1), m2.get(k2))))
            return i;
    }
    if (i1.hasNext())
        return 1;
    if (i2.hasNext())
        return -1;
    return 0;
}
2 голосов
/ 20 апреля 2010

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

1 голос
/ 20 апреля 2010

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

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

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

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

1 голос
/ 20 апреля 2010

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

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

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

0 голосов
/ 26 января 2013
public boolean equalMaps(Map<?, ?> map1, Map<?, ?>map2) {

    if (map1==null || map2==null || map1.size() != map2.size()) {
        return false;
    }

    for (Object key: map1.keySet()) {
        if (!map1.get(key).equals(map2.get(key))) {
            return false;
        }
    }
    return true;
}
0 голосов
/ 10 декабря 2012

@ paweloque Для сравнения двух объектов карты в Java вы можете добавить ключи карты в список, и с этими двумя списками вы можете использовать методы retainAll () и removeAll () и добавить их в другой список общих ключей и другие список ключей. Используя ключи общего списка и другого списка, вы можете перебирать карту, используя равные, вы можете сравнивать карты.

Приведенный ниже код выдаст следующий результат: До {zoo = barbar, foo = barbar} После {zoo = barbar, foo = barbar} Равно: До-Барбар После-Барбар Равно: До-Барбар После-Барбар </p> <pre><code>package com.demo.compareExample import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.apache.commons.collections.CollectionUtils; public class Demo { public static void main(String[] args) { Map<String, String> beforeMap = new HashMap<String, String>(); beforeMap.put("foo", "bar"+"bar"); beforeMap.put("zoo", "bar"+"bar"); Map<String, String> afterMap = new HashMap<String, String>(); afterMap.put(new String("foo"), "bar"+"bar"); afterMap.put(new String("zoo"), "bar"+"bar"); System.out.println("Before "+beforeMap); System.out.println("After "+afterMap); List<String> beforeList = getAllKeys(beforeMap); List<String> afterList = getAllKeys(afterMap); List<String> commonList1 = beforeList; List<String> commonList2 = afterList; List<String> diffList1 = getAllKeys(beforeMap); List<String> diffList2 = getAllKeys(afterMap); commonList1.retainAll(afterList); commonList2.retainAll(beforeList); diffList1.removeAll(commonList1); diffList2.removeAll(commonList2); if(commonList1!=null & commonList2!=null) // athough both the size are same { for (int i = 0; i < commonList1.size(); i++) { if ((beforeMap.get(commonList1.get(i))).equals(afterMap.get(commonList1.get(i)))) { System.out.println("Equal: Before- "+ beforeMap.get(commonList1.get(i))+" After- "+afterMap.get(commonList1.get(i))); } else { System.out.println("Unequal: Before- "+ beforeMap.get(commonList1.get(i))+" After- "+afterMap.get(commonList1.get(i))); } } } if (CollectionUtils.isNotEmpty(diffList1)) { for (int i = 0; i < diffList1.size(); i++) { System.out.println("Values present only in before map: "+beforeMap.get(diffList1.get(i))); } } if (CollectionUtils.isNotEmpty(diffList2)) { for (int i = 0; i < diffList2.size(); i++) { System.out.println("Values present only in after map: "+afterMap.get(diffList2.get(i))); } } } /**getAllKeys API adds the keys of the map to a list */ private static List<String> getAllKeys(Map<String, String> map1) { List<String> key = new ArrayList<String>(); if (map1 != null) { Iterator<String> mapIterator = map1.keySet().iterator(); while (mapIterator.hasNext()) { key.add(mapIterator.next()); } } return key; } }

...