17

在 java 中,我想比较两个地图,如下所示,我们是否有现有的 API 来执行此操作?

谢谢

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'
4

7 回答 7

31

我会使用 Set 的 removeAll() 功能来设置键的差异以查找添加和删除。可以通过使用作为 HashMap 的条目集进行集差来检测实际变化。Entry 使用键和值实现 equals()。

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

输出

added []
removed [b]
changed [c=333]
于 2012-05-14T16:16:37.053 回答
9

GuavaMaps类有一些方法可以计算一对地图之间的差异。但是,这些方法为您提供了一个表示差异的数据结构,而不是一个漂亮的字符串。

于 2012-05-14T16:10:02.793 回答
1

没有任何开箱即用的组件可以帮助解决这个问题。不幸的是,您可能不得不对其进行编码。好消息是逻辑很简单。

于 2012-05-14T16:03:44.623 回答
1

根据您的特定需求,您还可以考虑使用其他旨在完成这项工作的应用程序,例如 diff。您可以将这两个映射写入两个不同的文件,并对文件进行比较。

于 2012-05-14T16:08:46.837 回答
1

您可以使用包含键和值的自定义对象(实际上 Map 在内部执行此操作,对用户隐藏,因此我们不能使用它)

将这些元组放入Set

要比较两个集合,请将它们都转换为数组,对数组进行排序并从头到尾并行遍历两个数组,如果第一个数组的键小于第二个数组中的键,则降低第一个数组,反之亦然。

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++;
        }
    }
}
于 2012-05-14T16:11:30.697 回答
1
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);
于 2012-05-14T16:18:40.127 回答
0

@ user595234要比较两个映射,您可以将映射的键添加到列表中,对于这两个列表,您可以使用方法retainAll() 和removeAll() 并将它们添加到另一个公共键列表和不同的键列表中。使用公共列表和不同列表的键可以遍历映射,使用等于可以比较映射。

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

下面的代码会给你这个输出:

之前:{b=2, c=3, a=1}
之后:不相等:之前- {c=333, a=1}
3 之后- 333
相等:之前- 1 之后- 1
仅在之前映射中存在的值:2

于 2012-12-10T11:34:10.550 回答