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

时间:2010-04-20 09:44:06

标签: java collections map compare equals

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

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

由于

13 个答案:

答案 0 :(得分:35)

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

  1. 检查地图是否大小相同(!)
  2. 从一个地图中获取的集合
  3. 对于您检索到的每个组中的每个键,检查从该键的每个映射中检索的值是否相同(如果一个映射中缺少该键,则表示完全失败的相等)
  4. 换句话说(减去错误处理):

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

答案 1 :(得分:7)

您尝试使用串联构造不同的字符串将失败,因为它是在编译时执行的。这两张地图都有一对;每对都有“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”}的映射为毕竟,价值集是相等的。

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

答案 2 :(得分:6)

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

  • 获取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"

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

另见:


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

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

另见:

答案 3 :(得分:2)

因为你问过现成的Api ......以及Apache的公共资源。集合库有一个CollectionUtils类,它为集合操作/检查提供了易于使用的方法,例如交集,差异和联合。

答案 4 :(得分:2)

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

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

答案 5 :(得分:2)

这个问题很陈旧,但仍然相关。

如果您想按照与其键匹配的值比较两个地图,您可以执行以下操作:

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

答案 6 :(得分:1)

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

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

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

答案 7 :(得分:1)

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

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

比较2种不同的地图实现时,这样的工具会做什么,例如: - 一个映射允许空键 - map2.get(null)

上的另一个throw运行时异常

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

答案 8 :(得分:0)

您的示例中的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));

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

答案 9 :(得分:0)

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

以下代码将提供如下输出: 之前{zoo = barbar,foo = barbar} 在{zoo = barbar,foo = barbar}之后 相等:前 - barbar后 - barbar 相等:前 - barbar后 - 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;
    }
}

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

答案 10 :(得分:0)

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

答案 11 :(得分:0)

如果有人想在下面的Java 8流中做到这一点。

import java.util.HashMap;
import java.util.Map;

public class CompareTwoMaps {

    public static void main(String[] args) {

        Map<String, String> a = new HashMap<>();
        a.put("foo", "bar" + "bar");
        a.put("zoo", "bar" + "bar");

        Map<String, String> b = new HashMap<>();
        b.put(new String("foo"), "bar" + "bar");
        b.put(new String("zoo"), "bar" + "bar");

        System.out.println("result = " + areEqual(a, b));
    }

    private static boolean areEqual(Map<String, String> first, Map<String, String> second) {
        return first.entrySet().stream()
                .allMatch(e -> e.getValue().equals(second.get(e.getKey())));
    }
}

答案 12 :(得分:-2)

如果您想比较两个地图,则下面的代码可以帮助您

(new TreeMap<String, Object>(map1).toString().hashCode()) == new TreeMap<String, Object>(map2).toString().hashCode()