web-dev-qa-db-ja.com

2つのマップを値で比較する方法

2つのマップを値で比較するにはどうすればよいですか?等しい値を含む2つのマップがあり、それらをそれらの値で比較したい。次に例を示します。

    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を取得するには、コードをどのように変更すればよいですか?

12
paweloque

連結を使用して異なる文字列を作成しようとすると、コンパイル時に実行されるため失敗します。これらのマップは両方とも1つのペアを持っています。各ペアは、キーと値として「foo」と「barbar」を持ち、どちらも同じ文字列参照を使用します。

キーを参照せずに値のセットを比較したい場合は、次の場合にすぎません。

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

possibleは、map1.values()map2.values()を比較すると機能しますが、それらが返される順序が等値比較で使用される可能性もあります。これはあなたが望むものではありません。

上記のコードは{"a": "0"、 "b": "0"}と{"c": "0"}のマップが等しいと見なすため、セットの使用には独自の問題があることに注意してください。結局のところ、値セットは同じです。

あなたが望むもののより厳密な定義を提供することができれば、私たちがあなたに正しい答えを与えることを確実にすることはより簡単になります。

8
Jon Skeet

マップの値が等しいかどうかを比較する正しい方法は、次のとおりです。

  1. マップが同じサイズであることを確認してください(!)
  2. 1つのマップからkeysのセットを取得します
  3. 取得したセットの各キーについて、そのキーの各マップから取得した値が同じであることを確認します(キーが1つのマップに存在しない場合、それは完全に一致しないことを意味します)

言い換えると(マイナスのエラー処理):

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;
}
35
Donal Fellows

2つのマップの値が同じかどうかを確認するには、次のようにします。

  • Collection<V> values()ビューを取得する
  • _List<V>_にラップ
  • _Collections.sort_それらのリスト
  • 2つのリストがequalsかどうかをテストします

このようなものは動作します(ただし、その型の境界は改善できます)。

_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_ のため、これはO(N log N)です。

以下も参照してください。


keysが等しいかどうかをテストすることは、それらが_Set<K>_であるため、より簡単です。

_map1.keySet().equals(map2.keySet())
_

以下も参照してください。

6

この質問は古いですが、まだ関連しています。

キーに一致する値で2つのマップを比較する場合は、次のようにします。

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;
}
2
Manu Manjunath

これらはすべて等しいものを返します。それらは実際に比較を行っていないので、ソートに役立ちます。これはコンパレータのように動作します:

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

既製のApiについて聞いたので...まあApacheのコモンズ。コレクションライブラリには CollectionUtils クラスがあり、交差、差分など、コレクションの操作/チェックのための使いやすいメソッドを提供します、およびユニオン。

2
Narayan

2つのマップの同等性は非常にあいまいであり、開発者のニーズとマップの実装に依存するため、マップを比較するための「Apache-common-like」ツールはないと思います...

たとえば、Javaで2つのハッシュマップを比較する場合:-キー/値が同じであるかどうかを比較したい場合があります-キーの順序が同じである場合も比較したい場合があります-残りの容量が等しい場合も比較したい場合があります同じ...あなたは多くのものを比較することができます!

次のような2つの異なるマップ実装を比較するときに、このようなツールが実行すること:-1つのマップがnullキーを許可する-他がmap2.get(null)にランタイム例外をスローする

あなたは本当に何をする必要があるかに従ってあなた自身の解決策を実装するほうがいいです、そして私はあなたがすでにいくつかの答えを得ていると思います:)

1

重複する値がある可能性があると想定する場合、これを行う唯一の方法は、値をリストに入れ、それらを並べ替えてリストを比較することです。

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

値に重複する値を含めることができない場合は、セットを使用した並べ替えなしで上記のいずれかを実行できます。

1
Dean Povey

@paweloque Javaで2つのマップオブジェクトを比較する場合、リストにマップのキーを追加できます。これらの2つのリストを使用して、retainAll()メソッドとremoveAll()メソッドを使用し、別の共通キーリストと異なるキーリストに追加できます。共通リストと異なるリストのキーを使用してマップを反復処理し、イコールを使用してマップを比較できます。

以下のコードは次のような出力を提供します: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;
    }
}
</ code>
0
tinker_fairy

あなたの例の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));

文字列の連結はコンパイル時に行われるため、何の効果もありません。

0
Daff
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;
}
0
stones333