How to compare two maps by their values

前端 未结 13 917
囚心锁ツ
囚心锁ツ 2020-12-08 12:09

How to compare two maps by their values? I have two maps containing equal values and want to compare them by their values. Here is an example:

    Map a = ne         


        
相关标签:
13条回答
  • 2020-12-08 12:33

    The correct way to compare maps for value-equality is to:

    1. Check that the maps are the same size(!)
    2. Get the set of keys from one map
    3. For each key from that set you retrieved, check that the value retrieved from each map for that key is the same (if the key is absent from one map, that's a total failure of equality)

    In other words (minus error handling):

    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;
    }
    
    0 讨论(0)
  • 2020-12-08 12:41

    If you assume that there can be duplicate values the only way to do this is to put the values in lists, sort them and compare the lists viz:

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

    If values cannot contain duplicate values then you can either do the above without the sort using sets.

    0 讨论(0)
  • 2020-12-08 12:45

    To see if two maps have the same values, you can do the following:

    • Get their Collection<V> values() views
    • Wrap into List<V>
    • Collections.sort those lists
    • Test if the two lists are equals

    Something like this works (though its type bounds can be improved on):

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

    Test harness:

    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"
    

    This is O(N log N) due to Collections.sort.

    See also:

    • Collection<V> values()

    To test if the keys are equals is easier, because they're Set<K>:

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

    See also:

    • Set<K> keySet()
    0 讨论(0)
  • 2020-12-08 12:46

    This question is old, but still relevant.

    If you want to compare two maps by their values matching their keys, you can do as follows:

    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;
    }
    
    0 讨论(0)
  • 2020-12-08 12:46
    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;
    }
    
    0 讨论(0)
  • 2020-12-08 12:47

    Your attempts to construct different strings using concatenation will fail as it's being performed at compile-time. Both of those maps have a single pair; each pair will have "foo" and "barbar" as the key/value, both using the same string reference.

    Assuming you really want to compare the sets of values without any reference to keys, it's just a case of:

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

    It's possible that comparing map1.values() with map2.values() would work - but it's also possible that the order in which they're returned would be used in the equality comparison, which isn't what you want.

    Note that using a set has its own problems - because the above code would deem a map of {"a":"0", "b":"0"} and {"c":"0"} to be equal... the value sets are equal, after all.

    If you could provide a stricter definition of what you want, it'll be easier to make sure we give you the right answer.

    0 讨论(0)
提交回复
热议问题