如何根据值来比较两个地图

如何按价值比较两张地图? 我有两个包含相等值的地图,并希望通过它们的值进行比较。 这是一个例子:

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库中已经有一个库函数。

谢谢

您尝试使用串联构造不同的字符串将失败,因为它是在编译时执行的。 这两张地图都有一对; 每对都将使用“foo”和“barbar”作为键/值,两者都使用相同的字符串引用。

假设您确实想要比较值集而不引用任何键,它只是一个例子:

 Set values1 = new HashSet<>(map1.values()); Set values2 = new HashSet<>(map2.values()); boolean equal = values1.equals(values2); 

map1.values()map2.values()进行比较是可行的 – 但是它们返回的顺序也可能用于相等比较,这不是你想要的。

请注意,使用集合有其自身的问题 – 因为上面的代码会认为{“a”:“0”,“b”:“0”}和{“c”:“0”}的映射相等。毕竟,价值集是相等的。

如果你能对你想要的东西提供更严格的定义,那么确保我们给你正确答案会更容易。

比较地图的价值平等的正确方法是:

  1. 检查地图是否大小相同(!)
  2. 从一张地图中获取一组
  3. 对于您检索到的那个集合中的每个密钥,检查从该映射的每个映射中检索的值是否相同(如果一个映射中缺少该密钥,那么完全失败是相等的)

换句话说(减去error handling):

 boolean equalMaps(Mapm1, Mapm2) { if (m1.size() != m2.size()) return false; for (K key: m1.keySet()) if (!m1.get(key).equals(m2.get(key))) return false; return true; } 

要查看两个地图是否具有相同的值,您可以执行以下操作:

  • 获取他们的Collection values()视图
  • 包装到List
  • Collections.sort那些列表
  • 测试两个列表是否equals

这样的东西有效(虽然它的类型边界可以改进):

 static > boolean valuesEquals(Map map1, Map map2) { List values1 = new ArrayList(map1.values()); List values2 = new ArrayList(map2.values()); Collections.sort(values1); Collections.sort(values2); return values1.equals(values2); } 

测试工具:

 Map map1 = new HashMap(); map1.put("A", "B"); map1.put("C", "D"); Map map2 = new HashMap(); map2.put("A", "D"); map2.put("C", "B"); System.out.println(valuesEquals(map1, map2)); // prints "true" 

由于Collections.sort这是O(N log N)

也可以看看:

  • Collection values()

测试是否等于更容易,因为它们是Set

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

也可以看看:

  • Set keySet()

所有这些都是平等的。 他们实际上并没有进行比较,这对排序很有用。 这将更像是一个比较器:

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

这个问题很古老,但仍然相关。

如果要按照与其键匹配的值比较两个映射,可以执行以下操作:

 public static  boolean mapEquals(Map leftMap, Map 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; } 

既然你问过现成的Api ……那么Apache的公地。 集合库有一个CollectionUtils类,它为集合操作/检查提供了易于使用的方法,例如交集,差异和联合。

我不认为有一个“apache-common-like”工具来比较地图,因为2个地图的相等性非常模糊,取决于开发人员的需求和地图实现…

例如,如果您比较java中的两个哈希映射: – 您可能只想比较键/值是相同的 – 您可能还想比较键是否以相同的方式排序 – 您可能还想比较剩余容量是否同样的……你可以比较很多东西!

比较2个不同的地图实现时,这样的工具会做什么,以便: – 一个地图允许空键 – 另一个抛出运行时exception在map2.get(null)上

根据你真正需要做的事情,你最好实现自己的解决方案,我想你已经得到了一些答案:)

如果您认为可能存在重复值,则执行此操作的唯一方法是将值放入列表中,对它们进行排序并比较列表,即:

 List values1 = new ArrayList(map1.values()); List values2 = new ArrayList(map2.values()); Collections.sort(values1); Collections.sort(values2); boolean mapsHaveEqualValues = values1.equals(values2); 

如果值不能包含重复值,那么您可以执行上述操作而不使用集合进行排序。

您的示例中的equals结果显然是错误的,因为您将地图a与其中的某些值与空地图b(可能是复制和粘贴错误)进行比较。 我建议使用适当的变量名称(这样可以避免这些错误)并使用generics。

  Map first = new HashMap(); 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)); 

字符串的串联没有任何影响,因为它将在编译时完成。

@paweloque为了比较java中的两个地图对象,您可以将地图的键添加到列表中,使用这两个列表,您可以使用方法retainAll()和removeAll(),并将它们添加到另一个公共键列表和不同的键列表中。 使用公共列表和不同列表的键,您可以迭代地图,使用等于您可以比较地图。

下面的代码将给出如下输出:在{zoo = barbar,foo = barbar}之后{zoo = barbar,foo = barbar}等于:前 – barbar后 – barbar等于:before- barbar After-barbar

 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 beforeMap = new HashMap(); beforeMap.put("foo", "bar"+"bar"); beforeMap.put("zoo", "bar"+"bar"); Map afterMap = new HashMap(); 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 beforeList = getAllKeys(beforeMap); List afterList = getAllKeys(afterMap); List commonList1 = beforeList; List commonList2 = afterList; List diffList1 = getAllKeys(beforeMap); List 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 getAllKeys(Map map1) { List key = new ArrayList(); if (map1 != null) { Iterator mapIterator = map1.keySet().iterator(); while (mapIterator.hasNext()) { key.add(mapIterator.next()); } } return key; } } 

 public boolean equalMaps(Map map1, Mapmap2) { 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; } 

如果您想比较两个地图,那么下面的代码可能会对您有所帮助

 (new TreeMap(map1).toString().hashCode()) == new TreeMap(map2).toString().hashCode()