如何按价值比较两张地图?我有两个包含相等值的地图,并希望通过它们的值进行比较。这是一个例子:
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<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”}的映射相等。毕竟,价值集是相等的。
如果你能对你想要的东西提供更严格的定义,那么确保我们给你正确答案会更容易。
@paweloque为了比较java中的两个地图对象,您可以将地图的键添加到列表中,使用这两个列表,您可以使用方法retainAll()和removeAll(),并将它们添加到另一个公共键列表和不同的键列表中。使用公共列表和不同列表的键,您可以迭代地图,使用等于您可以比较地图。
下面的代码将给出如下输出:在{zoo = barbar,foo = barbar}之后{zoo = barbar,foo = barbar}等于:之前 - barbar后 - barbar Equal: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<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;
}
}
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;
}
如果您想比较两个地图,那么下面的代码可能会对您有所帮助
(new TreeMap<String, Object>(map1).toString().hashCode()) == new TreeMap<String, Object>(map2).toString().hashCode()
比较地图的价值平等的正确方法是:
换句话说(减去错误处理):
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;
}
要查看两个地图是否具有相同的值,您可以执行以下操作:
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())
所有这些都是平等的。它们实际上并没有进行比较,这对排序很有用。这将更像是一个比较器:
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 <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;
}
既然你问过现成的Api ......那就是Apache的公地。集合库有一个CollectionUtils类,它为集合操作/检查提供了易于使用的方法,例如交集,差异和联合。
我不认为有比较地图的“apache-common-like”工具,因为2个地图的相等性非常模糊,取决于开发人员的需求和地图实现......
例如,如果您比较java中的两个哈希映射: - 您可能只想比较键/值是相同的 - 您可能还想比较键是否以相同的方式排序 - 您可能还想比较剩余容量是否同样的...你可以比较很多东西!
比较2个不同的地图实现时,这样的工具会做什么,例如: - 一个地图允许空键 - 另一个抛出运行时异常在map2.get(null)上
你最好根据你真正需要做的事情来实现自己的解决方案,我想你已经得到了一些答案:)
如果您假设可能存在重复值,则执行此操作的唯一方法是将值放入列表中,对它们进行排序并比较列表,即:
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);
如果值不能包含重复值,那么您可以执行上述操作而不使用集合进行排序。
您的示例中的equals结果显然是错误的,因为您将地图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));
字符串的串联没有任何影响,因为它将在编译时完成。