如何比较两个地图的值

发布于 2024-08-29 16:36:59 字数 387 浏览 2 评论 0原文

如何比较两个地图的值?我有两个包含相同值的地图,想按它们的值进行比较。这是一个例子:

    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

我应该如何更改代码才能获得 true?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(13

森林散布 2024-09-05 16:36:59

比较映射值是否相等的正确方法是:

  1. 检查映射的大小是否相同(!)
  2. 从一个映射中获取一组
  3. 对于您检索到的该集中的每个键,请检查从每个映射中检索到的该键的值是相同的(如果一个映射中不存在该键,则完全相等)

换句话说(减去错误处理):

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

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;
}
羁绊已千年 2024-09-05 16:36:59

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

假设您确实想在不引用任何键的情况下比较值集,则只是以下情况:

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

map1.values()map2 进行比较可能 .values() 可以工作 - 但它们返回的顺序也可能用于相等比较,这不是您想要的。

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

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

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.

只有一腔孤勇 2024-09-05 16:36:59

要查看两个映射是否具有相同的值,您可以执行以下操作:

  • 获取它们的 Collection; value() 视图
  • 包装到 List
  • Collections.sort 这些列表
  • 测试两个列表是否等于

类似这样有效(尽管它的类型边界可以改进):

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

测试工具:

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"

由于Collections.sort

另请参阅:


要测试是否相等更容易,因为它们是Set

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

另请参阅:

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:

穿透光 2024-09-05 16:36:59

所有这些都返回平等。他们实际上并没有进行比较,这对于排序很有用。这将更像一个比较器:

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

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;
}
大姐,你呐 2024-09-05 16:36:59

这个问题很老了,但仍然相关。

如果您想通过值与键的匹配来比较两个映射,您可以执行以下操作:

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

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;
}
旧话新听 2024-09-05 16:36:59

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

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.

绿萝 2024-09-05 16:36:59

我不认为有一个“apache-common-like”工具来比较映射,因为 2 个映射的相等性非常模糊,并且取决于开发人员的需求和映射实现......

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

当比较两种不同的地图实现时,这样的工具会做什么:
- 一张地图允许空键
- 另一个在map2.get(null)上抛出运行时异常

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

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

寻找我们的幸福 2024-09-05 16:36:59

如果您假设可能存在重复值,则唯一的方法是将这些值放入列表中,对它们进行排序并比较列表,即:

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

殊姿 2024-09-05 16:36:59

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

家住魔仙堡 2024-09-05 16:36:59

@paweloque为了比较java中的两个映射对象,您可以将映射的键添加到列表中,对于这两个列表,您可以使用方法retainAll()和removeAll()并将它们添加到另一个公共键列表和不同键列表中。使用公共列表和不同列表的键可以迭代映射,使用 equals 可以比较映射。

下面的代码将给出如下输出:
在 {zoo=barbar, foo=barbar} 之前
在 {zoo=barbar, foo=barbar} 之后
等于: 前- barbar 后- barbar
等于: 前- barbar 后- 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;
    }
}

>

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

朱染 2024-09-05 16:36:59
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;
}
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;
}
多孤肩上扛 2024-09-05 16:36:59

如果有人想在 Java 8 流中做到这一点,下面就是例子。

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

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())));
    }
}
静水深流 2024-09-05 16:36:59

如果您想比较两个地图,下面的代码可能会帮助您

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

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()
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文