2016-04-29 3 views
3

Javaの2つのLinkedHashMapsの等価性をチェックしたいと思います。JavaのLinkedHashMapsの等価性をチェックする方法 - 挿入オーダーを考慮していますか?

equals() -methodはAbstractMapにあり、比較されたリストに同じキーと値が存在するかどうかをチェックして入力します。このように、挿入順序はチェックされません。

package com.stackoverflow.tests; 

import java.util.LinkedHashMap; 

public class LinkedHashMapEqualsTest { 

    public static void main(String[] args) { 
    LinkedHashMap<String, String> lhm1 = new LinkedHashMap<String, String>(); 
    lhm1.put("A", "1"); 
    lhm1.put("B", "2"); 
    lhm1.put("C", "3"); 
    LinkedHashMap<String, String> lhm2 = new LinkedHashMap<String, String>(); 
    lhm2.put("A", "1"); 
    lhm2.put("B", "2"); 
    lhm2.put("C", "3"); 
    LinkedHashMap<String, String> lhm3 = new LinkedHashMap<String, String>(); 
    lhm3.put("A", "1"); 
    lhm3.put("C", "3"); 
    lhm3.put("B", "2"); 
    LinkedHashMap<String, String> lhm4 = new LinkedHashMap<String, String>(); 
    lhm4.put("A", "1"); 
    lhm4.put("B", "2"); 
    LinkedHashMap<String, String> lhm5 = new LinkedHashMap<String, String>(); 
    lhm5.put("A", "2"); 
    lhm5.put("B", "2"); 
    lhm5.put("C", "3"); 

    if(lhm1.equals(lhm1)) { 
     System.out.println("Positive control. - SUCCESS"); 
    } 
    if(lhm1.equals(lhm2)) { 
     System.out.println("lhm1 does equal lhm2; as expected. - SUCCESS"); 
    } 
    if(lhm1.equals(lhm3)) { 
     System.out.println("lhm1 does equal lhm3, although the insert-order is different."); 
    } 
    if(!lhm1.equals(lhm4)) { 
     System.out.println("Negative control 1. - SUCCESS"); 
    } 
    if(!lhm1.equals(lhm5)) { 
     System.out.println("Negative control 2. - SUCCESS"); 
    } 

    } 

} 

はどのようにしても、挿入順序を比較リストの両方で同じであるかどうかを確認することができますか?任意の拡張せずにこれを行うための

+0

equalsメソッドをオーバーライドする必要があります。デフォルトでは、 'Abstract Map'のequals実装を使用します。その実装では、EntrySetの挿入順序を調べるために地図を反復処理する必要があります。 – SacJn

+3

パフォーマンスがそれほど重要ではない場合は、エントリセットからアレイリストを作成してみてください。新しいArrayList <>(lhm1.entrySet())。equals(新しいArrayList <>(lhm2.entrySet())) '。リストが等しくなるようにするには、それらの順序は同じでなければならず、LinkedHashMapのエントリセットにも挿入順序があるので、リストにもその順序があります。もちろん、エントリセットを直接操作するメソッドを作成することもできます。 – Thomas

答えて

5

私はおそらく、例えば、LinkedHashMapequals()をオーバーライドするが、ヘルパーメソッドを提供していないと思いますこの(AbstractList#equals(...)に触発さ)のように:

public static <K, V> boolean linkedEquals(LinkedHashMap<K, V> left, LinkedHashMap<K, V> right) { 
    Iterator<Entry<K, V>> leftItr = left.entrySet().iterator(); 
    Iterator<Entry<K, V>> rightItr = right.entrySet().iterator(); 

    while (leftItr.hasNext() && rightItr.hasNext()) { 
    Entry<K, V> leftEntry = leftItr.next(); 
    Entry<K, V> rightEntry = rightItr.next(); 

    //AbstractList does null checks here but for maps we can assume you never get null entries 
    if (! leftEntry.equals(rightEntry)) 
     return false; 
    } 
    return !(leftItr.hasNext() || rightItr.hasNext()); 
} 

次に、あなたがif(linkedEquals(lhm1, lhm3))のようにそれを使用しています。

編集:要求ごととして

、(これは複数の不要な反復に)低い性能をもたらすが、より少ないコードを記述する必要別の方法は、例えば、リストにエントリ・セットを変換し、それらを比較することであろう

if(new ArrayList<>(lhm1.entrySet()).equals(new ArrayList<>(lhm3.entrySet())) { ... } 
+0

あなたも他の解決策を投稿するべきです。 – SacJn

+1

私は第2の解決策をほぼ同じくらい好むわけではありません。 a)Map.Entryのequals()コントラクトが文書化されているので、常に両方のマップの完全な反復を行います。b)Map.Entryが正しくequalsを実装しています(実際には両方のバージョンがそうです)。 –

+0

b)しかしa)はa)については –

1

素朴な方法は、toString()出力を使用することです:

public static <K,V> boolean equalConsideringInsertionOrder(
    Map<K,V> left, Map<K,V> right){ 

    return left.toString().equals(right.toString()); 
} 

をしかし、コメントで指摘したように、このバージョンはややあやふやです。 toString()は正式な形式ではないので、そのように使うべきではありません。

より、精巧な効率的かつ正しいバージョンがこのようなものになるだろう:

public static <K, V> boolean equalConsideringInsertionOrder(
     Map<K, V> left, Map<K, V> right) { 

    Iterator<Map.Entry<K, V>> leftIterator = left.entrySet().iterator(); 
    Iterator<Map.Entry<K, V>> rightIterator = right.entrySet().iterator(); 
    while (leftIterator.hasNext() && rightIterator.hasNext()) { 
     Map.Entry<K, V> leftEntry = leftIterator.next(); 
     Map.Entry<K, V> rightEntry = rightIterator.next(); 
     if (!Objects.equals(leftEntry.getKey(), rightEntry.getKey()) 
       || !Objects.equals(leftEntry.getValue(),rightEntry.getValue())) { 
      return false; 
     } 
    } 
    return !leftIterator.hasNext() && !rightIterator.hasNext(); 
} 
+1

Uh uh uh ...等しい文字列表現は等しいオブジェクトと同じではありません。 2つの不等なオブジェクトは 'toString()'で同じ結果を生成することができます。 – mastov

+0

@mastov理論では、それは本当です。しかし、AbstractMapのすべての子孫は、toStringを実装する方法で非常に適切に動作します。 –

+1

私はマップについて話していません、私はキーと値について話しています。 – mastov

関連する問題