web-dev-qa-db-fra.com

Comment comparer deux cartes par leurs valeurs

Comment comparer deux cartes par leurs valeurs? J'ai deux cartes contenant des valeurs égales et je veux les comparer par leurs valeurs. Voici un exemple:

    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: quelqu'un s'il vous plaît éditer et corriger cette question pour signifier tout ce que c'est censé vouloir dire. Le code ci-dessus affiche "true" et non "false". ]]

Evidemment, pour mettre en place une comparaison peu compliquée, il suffit de comparer toutes les clés et leurs valeurs associées. Je ne crois pas que je sois le premier à le faire. Il doit donc déjà y avoir une bibliothèque de fonctions, soit en Java, soit dans l’une des bibliothèques jakarta.commons.

Merci

12
paweloque

Vos tentatives de construction de différentes chaînes à l'aide de la concaténation échoueront car elles sont exécutées au moment de la compilation. Ces deux cartes ont une seule paire. chaque paire aura "foo" et "barbar" comme clé/valeur, toutes deux utilisant la même référence de chaîne.

En supposant que vous souhaitiez réellement comparer les ensembles de valeurs sans aucune référence aux clés, il suffit de:

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

Il est possible que la comparaison de map1.values() avec map2.values() fonctionne, mais il est également possible que l'ordre dans lequel ils sont renvoyés soit utilisé dans la comparaison d'égalité, ce qui n'est pas ce que vous voulez.

Notez que l'utilisation d'un ensemble a ses propres problèmes, car le code ci-dessus considérerait une carte de {"a": "0", "b": "0"} et {"c": "0"} comme égales. .. les ensembles de valeurs sont égaux, après tout.

Si vous pouviez fournir une définition plus stricte de ce que vous voulez, il sera plus facile de vous assurer que nous vous donnons la bonne réponse.

7
Jon Skeet

La manière correcte de comparer les cartes pour l'égalité de valeur consiste à:

  1. Vérifiez que les cartes ont la même taille (!)
  2. Obtenir le jeu de clés depuis une carte
  3. Pour chaque clé de cet ensemble que vous avez récupérée, vérifiez que la valeur extraite de chaque carte pour cette clé est la même (si la clé est absente d'une carte, c'est un échec total de l'égalité).

En d'autres termes (moins le traitement des erreurs):

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

Pour voir si deux cartes ont les mêmes valeurs, vous pouvez procéder comme suit:

  • Obtenir leurs vues Collection<V> values()
  • Envelopper dans List<V>
  • Collections.sort ces listes
  • Teste si les deux listes sont equals

Quelque chose comme ceci fonctionne (bien que ses limites de type puissent être améliorées):

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

Harnais de test:

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"

Ceci est O(N log N) en raison de Collections.sort .

Voir également:


Pour vérifier si les keys sont égaux, c'est plus facile, car ils sont Set<K>:

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

Voir également:

6
polygenelubricants

Cette question est ancienne mais reste pertinente.

Si vous souhaitez comparer deux cartes dont les valeurs correspondent à leurs clés, procédez comme suit:

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.

Tous ceux-ci retournent égaux. Ils ne font pas réellement de comparaison, ce qui est utile pour le tri. Cela se comportera plutôt comme un comparateur:

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

Puisque vous avez posé des questions sur les produits Api prêts à l'emploi, les biens communs d'Apache. La bibliothèque de collections a une classe CollectionUtils qui fournit des méthodes faciles à utiliser pour la manipulation/vérification de collections, telles que l'intersection, la différence et l'union.

2
Narayan

Je ne pense pas qu'il existe un outil "similaire à Apache" pour comparer des cartes, car l'égalité de 2 cartes est très ambiguë et dépend des besoins du développeur et de la mise en œuvre de la carte ...

Par exemple, si vous comparez deux hashmaps en Java: - Vous voudrez peut-être simplement comparer les clés/les valeurs sont les mêmes - Vous pouvez également vouloir comparer si les clés sont classées de la même façon. Vous voulez également comparer si la capacité restante est la même .__ Vous pouvez comparer beaucoup de choses!

Ce que ferait un tel outil lors de la comparaison de 2 implémentations de carte différentes, telles que: - Une carte autorise les clés nulles - L'autre exception d'exécution sur map2.get (null)

Vous feriez mieux de mettre en œuvre votre propre solution en fonction de ce que vous devez vraiment faire, et je pense que vous avez déjà quelques réponses ci-dessus :)

1
Sebastien Lorber

Si vous supposez qu'il peut y avoir des valeurs en double, le seul moyen de le faire est de les placer dans des listes, de les trier et de les comparer, à savoir

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

Si les valeurs ne peuvent pas contenir de doublons, vous pouvez soit procéder comme indiqué ci-dessus sans le tri à l'aide d'ensembles.

1
Dean Povey

@paweloque Pour comparer deux objets de carte en Java, vous pouvez ajouter les clés d'une carte à lister. Avec ces 2 listes, vous pouvez utiliser les méthodes retenueAll () et removeAll () et les ajouter à une autre liste de clés commune et à une autre liste de clés. En utilisant les touches de la liste commune et des listes différentes, vous pouvez parcourir la carte, en utilisant égal, vous pouvez comparer les cartes.

Le code ci-dessous donnera les résultats suivants: 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

Le résultat d'égal à égal dans votre exemple est évidemment faux car vous comparez la carte a avec certaines valeurs qu'elle contient avec une carte vide b (probablement une erreur de copier-coller). Je recommande d'utiliser des noms de variable appropriés (afin d'éviter ce type d'erreur) et d'utiliser également des génériques.

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

La concaténation de vos chaînes n'a aucun effet car elle sera faite au moment de la compilation.

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