[java] How to compare two maps by their values

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 = 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

How should I change the code to obtain a true?

This question is related to java dictionary collections compare equals

The answer is


If you want to compare two Maps then, below code may help you

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

Since you asked about ready-made Api's ... well Apache's commons. collections library has a CollectionUtils class that provides easy-to-use methods for Collection manipulation/checking, such as intersection, difference, and union.


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:


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

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

See also:


All of these are returning equals. They arent actually doing a comparison, which is useful for sort. This will behave more like a comparator:

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

The result of equals in your example is obviously false because you are comparing the map a with some values in it with an empty map b (probably a copy and paste error). I recommend to use proper variable names (so you can avoid these kinds of errors) and make use of generics, too.

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

The concatenation of your strings doesn't have any effect because it will be done at compile time.


@paweloque For Comparing two Map Objects in java, you can add the keys of a map to list and with those 2 lists you can use the methods retainAll() and removeAll() and add them to another common keys list and different keys list. Using the keys of the common list and different list you can iterate through map, using equals you can compare the maps.

The below code will give output like this: Before {zoo=barbar, foo=barbar} After {zoo=barbar, foo=barbar} Equal: Before- barbar After- 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;
    }
}


I don't think there is a "apache-common-like" tool to compare maps since the equality of 2 maps is very ambiguous and depends on the developer needs and the map implementation...

For exemple if you compare two hashmaps in java: - You may want to just compare key/values are the same - You may also want to compare if the keys are ordered the same way - You may also want to compare if the remaining capacity is the same ... You can compare a lot of things!

What such a tool would do when comparing 2 different map implementations such that: - One map allow null keys - The other throw runtime exception on map2.get(null)

You'd better to implement your own solution according to what you really need to do, and i think you already got some answers above :)


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.


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

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

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

If anyone is looking to do it in Java 8 streams below is the example.

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

Examples related to java

Under what circumstances can I call findViewById with an Options Menu / Action Bar item? How much should a function trust another function How to implement a simple scenario the OO way Two constructors How do I get some variable from another class in Java? this in equals method How to split a string in two and store it in a field How to do perspective fixing? String index out of range: 4 My eclipse won't open, i download the bundle pack it keeps saying error log

Examples related to dictionary

JS map return object python JSON object must be str, bytes or bytearray, not 'dict Python update a key in dict if it doesn't exist How to update the value of a key in a dictionary in Python? How to map an array of objects in React C# Dictionary get item by index Are dictionaries ordered in Python 3.6+? Split / Explode a column of dictionaries into separate columns with pandas Writing a dictionary to a text file? enumerate() for dictionary in python

Examples related to collections

Kotlin's List missing "add", "remove", Map missing "put", etc? How to unset (remove) a collection element after fetching it? How can I get a List from some class properties with Java 8 Stream? Java 8 stream map to list of keys sorted by values How to convert String into Hashmap in java How can I turn a List of Lists into a List in Java 8? MongoDB Show all contents from all collections Get nth character of a string in Swift programming language Java 8 Distinct by property Is there a typescript List<> and/or Map<> class/library?

Examples related to compare

Checking for duplicate strings in JavaScript array How to compare two files in Notepad++ v6.6.8 How to compare LocalDate instances Java 8 Comparing the contents of two files in Sublime Text comparing elements of the same array in java How to compare two dates along with time in java bash string compare to multiple correct values Query comparing dates in SQL How to compare two java objects Comparing two integer arrays in Java

Examples related to equals

this in equals method Why do we have to override the equals() method in Java? Compare two objects with .equals() and == operator Check if bash variable equals 0 Setting equal heights for div's with jQuery Java, how to compare Strings with String Arrays How can I express that two values are not equal to eachother? How to override equals method in Java How do you say not equal to in Ruby? Getting an element from a Set