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