user595234
user595234

Reputation: 6259

Java compare two map

In java, I want to compare two maps, like below, do we have existing API to do this ?

Thanks

Map<String, String> beforeMap ;
beforeMap.put("a", "1");
beforeMap.put("b", "2");
beforeMap.put("c", "3");

Map<String, String> afterMap ;
afterMap.put("a", "1");
afterMap.put("c", "333");

//--- it should give me:
b is missing, c value changed from '3' to '333'

Upvotes: 17

Views: 16662

Answers (7)

tinker_fairy
tinker_fairy

Reputation: 1351

@user595234 To Compare the two Maps 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.

    public class Demo
    {
           public static void main(String[] args) 
            {
                Map<String, String> beforeMap = new HashMap<String, String>();
                beforeMap.put("a", "1");
                beforeMap.put("b", "2");
                beforeMap.put("c", "3");

                Map<String, String> afterMap = new HashMap<String, String>();
                afterMap.put("a", "1");
                afterMap.put("c", "333");

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

                System.out.println("Common List of before map "+commonList1);
                System.out.println("Common List of after map "+commonList2);
                System.out.println("Diff List of before map "+diffList1);
                System.out.println("Diff List of after map "+diffList2);

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

The below code will give you this output:

Before: {b=2, c=3, a=1}
After: {c=333, a=1}
Unequal: Before- 3 After- 333
Equal: Before- 1 After- 1
Values present only in before map: 2

Upvotes: 0

Mark Jeronimus
Mark Jeronimus

Reputation: 9543

You could use a custom object that contains the key and the value (actually Map does this internally, hidden from the user, so we can't use that)

Put these tuples into a Set

To compare two sets, convert them both to arrays, sort the arrays and walk both arrays from begin to end in parallel, stepping down the first array if it's key is smaller than the key in the second array, and vise versa.

class Tuple implements Comparable<Tuple>
{
    public String   key;
    public String   value;

    public Tuple(String key, String value)
    {
        this.key = key;
        this.value = value;
    }

    @Override
    public int compareTo(Tuple o)
    {
        return key.compareTo(o.key);
    }
}

public static void main(String[] args)
{
    // TreeSet is already sorted. If you use HashSet, use Arrays.sort()
    Set<Tuple> beforeSet = new TreeSet<>();
    beforeSet.add(new Tuple("a", "1"));
    beforeSet.add(new Tuple("b", "2"));
    beforeSet.add(new Tuple("c", "4"));

    Set<Tuple> afterSet = new TreeSet<>();
    afterSet.add(new Tuple("a", "1"));
    afterSet.add(new Tuple("c", "333"));
    afterSet.add(new Tuple("aa", "4"));

    Tuple[] beforeArray = beforeSet.toArray(new Tuple[beforeSet.size()]);
    Tuple[] afterArray = afterSet.toArray(new Tuple[afterSet.size()]);

    int beforePtr = 0;
    int afterPtr = 0;
    while (beforePtr < beforeArray.length || afterPtr < afterArray.length)
    {
        int difference = afterPtr >= afterArray.length? -1 : beforePtr >= beforeArray.length? 1 : beforeArray[beforePtr].compareTo(afterArray[afterPtr]);
        if (difference == 0)
        {
            if (!beforeArray[beforePtr].value.equals(afterArray[afterPtr].value))
            {
                System.out.println(beforeArray[beforePtr].key + " value changed from '" + beforeArray[beforePtr].value + "' to '" + afterArray[afterPtr].value + "'");
            }
            beforePtr++;
            afterPtr++;
        }
        else if (difference < 0)
        {
            System.out.println(beforeArray[beforePtr].key + " is missing");
            beforePtr++;
        }
        else
        {
            System.out.println(afterArray[afterPtr].key + " is added");
            afterPtr++;
        }
    }
}

Upvotes: 1

sjakubowski
sjakubowski

Reputation: 2943

String output = new String();
for (String key:beforeMap.getKeys()){
  String beforeValue = beforeMap.getValue(key);
  String afterValue = afterMap.getValue(key);
  //nullsafe
  if(beforeValue.equals(afterValue){}
  else if (afterValue == null){
      output = output + key + " is missing, ";
      continue;
  }else {
      output = output + key + " has changed from " + beforeValue + " to " + afterValue + " , ";
  }
  afterMap.remove(key);

}

for (String key:afterMap.getKeys()){
    output = output + key + " was added with value " + afterMap.getValue(key) + ", ";
}

if(output == null){
    output = "Same map";
}
output = output.substring(0,output.length-2);
System.out.println(output);

Upvotes: 1

Adam
Adam

Reputation: 36703

I'd use removeAll() functionality of Set to to do set differences of keys to find additions and deletions. Actual changes can be detected by doing a set difference using the entry set as HashMap.Entry implements equals() using both key and value.

Set<String> removedKeys = new HashSet<String>(beforeMap.keySet());
removedKeys.removeAll(afterMap.keySet());

Set<String> addedKeys = new HashSet<String>(afterMap.keySet());
addedKeys.removeAll(beforeMap.keySet());

Set<Entry<String, String>> changedEntries = new HashSet<Entry<String, String>>(
        afterMap.entrySet());
changedEntries.removeAll(beforeMap.entrySet());

System.out.println("added " + addedKeys);
System.out.println("removed " + removedKeys);
System.out.println("changed " + changedEntries);

Output

added []
removed [b]
changed [c=333]

Upvotes: 31

Stephen C
Stephen C

Reputation: 718836

The Guava Maps class has some methods for calulating the differences between a pair of maps. However, these methods give you a data structure representing the differences not a pretty-printed string.

Upvotes: 9

atk
atk

Reputation: 9314

Depending upon your particular needs, you might also consider using other applications designed to do this work, like diff. You could write the two maps to two different files, and diff the files.

Upvotes: 1

mprivat
mprivat

Reputation: 21902

There isn't any out of the box component to help with that. You'll probably have to code it unfortunately. The good news is the logic is pretty easy.

Upvotes: 1

Related Questions