代码之家  ›  专栏  ›  技术社区  ›  paweloque

如何按值比较两个地图

  •  12
  • paweloque  · 技术社区  · 14 年前

    如何按值比较两个地图?我有两个包含相等值的映射,希望按它们的值进行比较。下面是一个例子:

        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中或者在一个库中一定有一个库函数。

    谢谢

    12 回复  |  直到 6 年前
        1
  •  7
  •   k1eran    9 年前

    使用连接构造不同字符串的尝试将失败,因为它是在编译时执行的。这两个映射都有一对;每一对都将使用相同的字符串引用,将“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
  •  35
  •   luksmir    11 年前

    比较映射值相等性的正确方法是:

    1. 检查地图大小是否相同(!)
    2. 得到一套 钥匙 从一张地图上
    3. 对于从检索到的该集中的每个键,请检查从该键的每个映射检索到的值是否相同(如果该键在一个映射中不存在,则表示完全不相等)

    换句话说(减去错误处理):

    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;
    }
    
        3
  •  6
  •   polygenelubricants    14 年前

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

    • 得到他们 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())
    

    参见:

        4
  •  2
  •   Dana    12 年前

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

    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
  •   Manu Manjunath    9 年前

    这个问题已经过时了,但仍然有意义。

    如果要通过两个映射的值与其键匹配来比较它们,可以执行以下操作:

    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
  •  2
  •   arghtype Castaldi    6 年前

    既然你问过现成的API…阿帕奇的公地。集合库具有 CollectionUtils 类,该类为集合操作/检查提供易于使用的方法,例如交集、差集和并集。

        7
  •  1
  •   Sebastien Lorber    14 年前

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

    如果您比较Java中的两个哈希图,则为: -您可能只想比较键/值是否相同 -您可能还想比较钥匙的顺序是否相同 -您可能还想比较剩余容量是否相同 …你可以比较很多东西!

    当比较两种不同的映射实现时,这样的工具会做什么: -一个映射允许空键 -map2.get上的另一个throw运行时异常(null)

    你最好根据自己的实际需要来实现自己的解决方案,我想你已经得到了上面的一些答案:)

        8
  •  1
  •   Dean Povey    14 年前

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

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

    如果值不能包含重复的值,则可以在不使用集合排序的情况下执行上述操作。

        9
  •  0
  •   Daff    14 年前

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

    字符串的连接没有任何效果,因为它将在编译时完成。

        10
  •  0
  •   tinker_fairy    12 年前

    为了比较Java中的两个MAP对象,可以将一个映射的键添加到列表中,使用这2个列表,可以使用方法RealPalm()和ReaveLay.()并将它们添加到另一个公共密钥列表和不同的密钥列表中。使用common list和different list的键可以遍历map,使用equals可以比较map。

    下面的代码将给出如下输出: 在{zoo=barbar,foo=barbar}之前 在{zoo=barbar,foo=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;
        }
    }
    

        11
  •  0
  •   stones333    11 年前
    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;
    }
    
        12
  •  -2
  •   Azee Md    12 年前

    如果你想比较两张地图,下面的代码可以帮助你

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