Сравнение двух карт


у меня есть две карты, объявленные как Map<String, Object>. Элемент Object здесь может быть другой Map<String, Object> (и так далее). Я хочу проверить, являются ли две карты точно такими же, не зная их глубины. Вместо использования рекурсии я могу сравнить выходные данные toString() позвонил на каждой карте? Или есть более простой способ сравнить карты?

3   51   2014-07-18 02:29:32

3 ответа:

Быстрый Ответ

вы должны использовать equals метод, так как это реализовано для выполнения сравнения, которые вы хотите. toString() сам использует итератор так же, как equals но это более неэффективный подход. Кроме того, как указал @Teepeemm,toString зависит от порядка элементов (в основном порядок возврата итератора), следовательно, не гарантируется предоставление одного и того же вывода для 2 разных карт (особенно если мы сравниваем две разные карты).

Примечание/Предупреждения: ваш вопрос и мой ответ предполагают, что классы, реализующие интерфейс map, уважают ожидаемое toString и equals поведение. Классы java по умолчанию делают это, но пользовательский класс карты должен быть проверен, чтобы проверить ожидаемое поведение.

см.:http://docs.oracle.com/javase/7/docs/api/java/util/Map.html

boolean equals(Object o)

сравнивает указанный объект с этой картой для равенства. Возвращается истинный если данный объект также является картой и двумя картами представляют то же самое сопоставления. Более формально, две карты m1 и m2 представляют собой то же самое отображения если М1.entrySet().равно (м2.entrySet()). Это гарантирует, что метод equals работает правильно в разных реализациях Интерфейс карты.

реализация в источнике Java (java.утиль.AbstractMap)

кроме того, сама java заботится об итерации все элементы и делает сравнение так что вам не придется. Взгляните на реализацию AbstractMap который используется классами, такими как HashMap:

 // Comparison and hashing

    /**
     * Compares the specified object with this map for equality.  Returns
     * <tt>true</tt> if the given object is also a map and the two maps
     * represent the same mappings.  More formally, two maps <tt>m1</tt> and
     * <tt>m2</tt> represent the same mappings if
     * <tt>m1.entrySet().equals(m2.entrySet())</tt>.  This ensures that the
     * <tt>equals</tt> method works properly across different implementations
     * of the <tt>Map</tt> interface.
     *
     * <p>This implementation first checks if the specified object is this map;
     * if so it returns <tt>true</tt>.  Then, it checks if the specified
     * object is a map whose size is identical to the size of this map; if
     * not, it returns <tt>false</tt>.  If so, it iterates over this map's
     * <tt>entrySet</tt> collection, and checks that the specified map
     * contains each mapping that this map contains.  If the specified map
     * fails to contain such a mapping, <tt>false</tt> is returned.  If the
     * iteration completes, <tt>true</tt> is returned.
     *
     * @param o object to be compared for equality with this map
     * @return <tt>true</tt> if the specified object is equal to this map
     */
    public boolean equals(Object o) {
        if (o == this)
            return true;

        if (!(o instanceof Map))
            return false;
        Map<K,V> m = (Map<K,V>) o;
        if (m.size() != size())
            return false;

        try {
            Iterator<Entry<K,V>> i = entrySet().iterator();
            while (i.hasNext()) {
                Entry<K,V> e = i.next();
                K key = e.getKey();
                V value = e.getValue();
                if (value == null) {
                    if (!(m.get(key)==null && m.containsKey(key)))
                        return false;
                } else {
                    if (!value.equals(m.get(key)))
                        return false;
                }
            }
        } catch (ClassCastException unused) {
            return false;
        } catch (NullPointerException unused) {
            return false;
        }

        return true;
    }

сравнение двух различных типов карт

toString терпит неудачу при сравнении TreeMap и HashMap хотя equals делает сравнение содержимого правильно.

код:

public static void main(String args[]) {
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("2", "whatever2");
map.put("1", "whatever1");
TreeMap<String, Object> map2 = new TreeMap<String, Object>();
map2.put("2", "whatever2");
map2.put("1", "whatever1");

System.out.println("Are maps equal (using equals):" + map.equals(map2));
System.out.println("Are maps equal (using toString().equals()):"
        + map.toString().equals(map2.toString()));

System.out.println("Map1:"+map.toString());
System.out.println("Map2:"+map2.toString());
}

выход:

Are maps equal (using equals):true
Are maps equal (using toString().equals()):false
Map1:{2=whatever2, 1=whatever1}
Map2:{1=whatever1, 2=whatever2}

пока вы переопределяете equals() на каждый ключ и значение, содержащееся в карте, то m1.equals(m2) должен быть надежным, чтобы проверить равенство карт.

тот же результат можно получить и путем сравнения toString() каждой карте, как вы предложили, но с помощью equals() - Это более интуитивный подход.

может быть не ваша конкретная ситуация, но если вы храните массивы на карте, может быть немного сложнее, потому что они должны быть сравнены значение по значению, или с помощью Arrays.equals(). Новые подробности об этом см. здесь.

Я сделал этот тест и работает:

 import java.util.HashMap; import java.util.Map;
 import java.util.TreeMap; import org.junit.Assert;
 import org.junit.Test;
 ...
 private void put(String key, String value, Map<String,String> map1, Map<String, String> map2){
    map1.put(key, value);
    map2.put(key, value);
}

@Test
public void testEqualsMap() throws Exception {
    Map<String, String> hashmap = new HashMap<String, String>();
    Map<String, String> treemap = new TreeMap<String, String>();
    put("voltage", "110/220", treemap, hashmap);
    put("color", "blue", treemap, hashmap);
    Assert.assertTrue(hashmap.equals(treemap));

    treemap.put("color", "red");
    Assert.assertFalse(hashmap.equals(treemap));
}