wake-up-neo.com

So vergleichen Sie zwei Karten anhand ihrer Werte

Wie kann man zwei Karten nach ihren Werten vergleichen? Ich habe zwei Karten mit gleichen Werten und möchte sie anhand ihrer Werte vergleichen. Hier ist ein Beispiel:

    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

    .... what to call to obtain a true?

[[ EDIT: Jemand bitte editieren und diese Frage korrigieren, um zu bedeuten, was immer sie eigentlich bedeuten soll. Der obige Code gibt "true" aus, nicht "false". ]]

Um einen Vergleich zu implementieren, ist es natürlich nicht schwierig, alle Schlüssel und die zugehörigen Werte miteinander zu vergleichen. Ich glaube nicht, dass ich der erste bin, der dies tut, also muss es bereits eine Bibliotheksfunktion in Java oder in einer der Bibliotheken von jakarta.commons geben.

Vielen Dank

12
paweloque

Ihre Versuche, verschiedene Zeichenfolgen mithilfe von Verkettung zu erstellen, schlagen fehl, da sie zur Kompilierzeit ausgeführt werden. Beide Karten haben ein einzelnes Paar; Jedes Paar hat "foo" und "barbar" als Schlüssel/Wert, wobei beide denselben String-Verweis verwenden.

Angenommen, Sie möchten die Wertesätze wirklich ohne Schlüsselbezug vergleichen, es handelt sich lediglich um Folgendes:

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

Es ist möglich dass der Vergleich von map1.values() mit map2.values() funktioniert - aber es ist auch möglich, dass die Reihenfolge, in der sie zurückgegeben werden, im Gleichheitsvergleich verwendet wird, was Sie nicht wollen.

Beachten Sie, dass die Verwendung eines Sets seine eigenen Probleme hat - weil der obige Code eine Zuordnung von {"a": "0", "b": "0"} und {"c": "0"} für gleich halten würde. .. die Wertemengen sind schließlich gleich.

Wenn Sie eine genauere Definition Ihrer Wünsche angeben könnten, ist es einfacher, sicherzustellen, dass wir Ihnen die richtige Antwort geben.

7
Jon Skeet

Der richtige Weg zum Vergleichen von Karten für die Wertgleichheit ist:

  1. Überprüfen Sie, ob die Karten die gleiche Größe haben (!).
  2. Holen Sie sich die Tasten von einer Karte
  3. Überprüfen Sie für jeden Schlüssel aus dieser Gruppe, den Sie abgerufen haben, dass der aus jeder Karte für diesen Schlüssel abgerufene Wert derselbe ist (wenn der Schlüssel in einer Karte nicht vorhanden ist, ist dies ein völliger Fehler der Gleichheit).

Mit anderen Worten (minus Fehlerbehandlung):

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

Um zu sehen, ob zwei Karten die gleichen Werte haben, können Sie Folgendes tun:

  • Erhalten Sie ihre Collection<V> values()-Ansichten
  • In List<V> einwickeln
  • Collections.sort diese Listen
  • Testen Sie, ob die beiden Listen equals sind.

So etwas funktioniert (obwohl die Typgrenzen verbessert werden können):

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

Testgeschirr:

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"

Dies ist O(N log N) aufgrund von Collections.sort .

Siehe auch:


Um zu testen, ob die keys gleich sind, ist es einfacher, da sie Set<K> sind:

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

Siehe auch:

6

Diese Frage ist alt, aber immer noch relevant.

Wenn Sie zwei Karten anhand ihrer Werte vergleichen möchten, die ihren Schlüsseln entsprechen, können Sie Folgendes tun:

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

Alle diese sind gleichwertig. Sie machen eigentlich keinen Vergleich, was für die Sortierung nützlich ist. Dies wird sich eher wie ein Vergleicher verhalten:

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

Da haben Sie nach vorgefertigten Apis gefragt ... na ja, Apaches Commons. Collections-Bibliothek verfügt über eine CollectionUtils -Klasse, die benutzerfreundliche Methoden für die Manipulation/Überprüfung von Collection-Elementen bietet, z. B. Schnittmenge, Differenz und Vereinigung.

2
Narayan

Ich glaube nicht, dass es ein "Apache-Common-like" -Werkzeug zum Vergleichen von Karten gibt, da die Gleichheit von 2 Karten sehr vieldeutig ist und von den Anforderungen des Entwicklers und der Kartenimplementierung abhängt ...

Zum Beispiel, wenn Sie zwei Hashmaps in Java vergleichen: - Möglicherweise möchten Sie nur Schlüssel vergleichen/Werte sind dieselben - Möglicherweise möchten Sie auch vergleichen, ob die Schlüssel gleich angeordnet sind - Sie können möchten auch vergleichen, ob die verbleibende Kapazität gleich ist ... Sie können eine Menge Dinge vergleichen!

Was würde ein solches Tool tun, wenn Sie zwei verschiedene Kartenimplementierungen miteinander vergleichen, z. B .: __- Eine Karte lässt NULL-Schlüssel zu- Die andere Ausnahme für die Laufzeitauslösung für map2.get (null)

Sie sollten besser Ihre eigene Lösung implementieren, je nachdem, was Sie wirklich tun müssen, und ich glaube, Sie haben oben bereits einige Antworten erhalten :)

1

Wenn Sie davon ausgehen, dass es doppelte Werte geben kann, besteht die einzige Möglichkeit darin, die Werte in Listen einzufügen, sie zu sortieren und die Listen zu vergleichen:

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

Wenn Werte keine doppelten Werte enthalten können, können Sie entweder die obigen Schritte ausführen, ohne mithilfe von Sets sortieren zu müssen.

1
Dean Povey

@paweloque Zum Vergleichen von zwei Kartenobjekten in Java können Sie die Schlüssel einer Karte zur Liste hinzufügen. Mit diesen beiden Listen können Sie die Methoden retainAll () und removeAll () verwenden und sie zu einer anderen allgemeinen Schlüsselliste und einer anderen Schlüsselliste hinzufügen. Mit den Schlüsseln der allgemeinen Liste und einer anderen Liste können Sie durch die Karte iterieren und mit Gleichheit die Karten vergleichen.

Der folgende Code gibt eine Ausgabe wie folgt aus: Vor {Zoo = barbar, foo = barbar} Nach {Zoo = barbar, foo = barbar} Gleich: Vor-barbar Nach-barbar Gleich: Vor-barbar Nach-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

Das Ergebnis von equals in Ihrem Beispiel ist offensichtlich falsch, da Sie die Karte a mit einigen Werten mit einer leeren Karte b vergleichen (wahrscheinlich ein Fehler beim Kopieren und Einfügen). Ich empfehle, die richtigen Variablennamen zu verwenden (damit Sie solche Fehler vermeiden können) und auch Generics zu verwenden.

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

Die Verkettung Ihrer Zeichenfolgen hat keine Auswirkungen, da sie zur Kompilierzeit ausgeführt wird.

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