Java 如何按值比较两张地图

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2674021/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 10:40:22  来源:igfitidea点击:

How to compare two maps by their values

javadictionarycollectionscompareequals

提问by paweloque

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?

我应该如何更改代码以获得真实的?

采纳答案by Jon Skeet

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.

您尝试使用连接构造不同的字符串将失败,因为它是在编译时执行的。这两张地图都有一对;每对都有“foo”和“barbar”作为键/值,两者都使用相同的字符串引用。

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 possiblethat 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.

可能是比较map1.values()map2.values()将工作-但它也有可能是在他们返回的顺序将在平等的比较,这是不是你想要的使用。

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.

请注意,使用集合有其自身的问题——因为上面的代码会认为 {"a":"0", "b":"0"} 和 {"c":"0"} 的映射是相等的。 .. 毕竟,值集是相等的。

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

如果您可以对您想要的内容提供更严格的定义,则更容易确保我们为您提供正确的答案。

回答by polygenelubricants

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.sortthose lists
  • Test if the two lists are equals
  • 获取他们的Collection<V> values()意见
  • 换入 List<V>
  • Collections.sort那些名单
  • 测试两个列表是否是 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.

这是O(N log N)由于Collections.sort.

See also:

也可以看看:



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

测试是否相等更容易,因为它们是Set<K>

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

See also:

也可以看看:

回答by Daff

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.

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

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

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

回答by Dean Povey

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.

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

回答by Donal Fellows

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 keysfrom 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)
  1. 检查地图大小是否相同(!)
  2. 从一张地图中获取一组
  3. 对于您检索到的那个集合中的每个键,检查从每个映射中为该键检索的值是否相同(如果一个映射中不存在该键,则完全不相等)

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

回答by Sebastien Lorber

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

我不认为有一个“类似 apache-common-like”的工具来比较地图,因为 2 张地图的相等性非常不明确,取决于开发人员的需求和地图实现......

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!

例如,如果您比较 Java 中的两个哈希图: - 您可能只想比较键/值是否相同 - 您可能还想比较键的排序方式是否相同 - 您可能还想比较剩余容量是否为一样的......你可以比较很多东西!

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)

当比较 2 个不同的地图实现时,这样的工具会做什么: - 一个地图允许空键 - 另一个在 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 :)

你最好根据你真正需要做的事情来实现你自己的解决方案,我想你上面已经有了一些答案:)

回答by Narayan

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

既然您询问了现成的 Api ......以及 Apache 的公共资源。collections 库有一个CollectionUtils类,它提供了易于使用的集合操作/检查方法,例如交集、差异和并集。

回答by Dana

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

回答by Azee Md

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

回答by tinker_fairy

@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.

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

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

下面的代码将给出这样的输出: 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;
    }
}
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;
    }
}