web-dev-qa-db-fra.com

Comment puis-je vérifier si deux ArrayList diffèrent, peu m'importe ce qui a changé

Comment puis-je vérifier si deux ArrayLists diffèrent l'une de l'autre? Je me fiche de la différence, je veux juste savoir si ce n'est pas pareil.

Je récupère la liste des scores dans une base de données toutes les minutes, et seulement si la liste des scores que j'ai récupérée est différente de celle que j'ai récupérée il y a une minute, je veux l'envoyer au client.

Maintenant, la valeur de ArrayList est en fait une classe que j'ai créée (qui contient le nom, le niveau, le rang, le score).

Dois-je implémenter equals() dessus?

37
ufk

Voici une méthode simple qui vérifie si 2 listes de tableaux contiennent les mêmes valeurs quel que soit leur ordre.

 //the name of the method explains it well...
    public boolean isTwoArrayListsWithSameValues(ArrayList<Object> list1, ArrayList<Object> list2)
    {
        //null checking
        if(list1==null && list2==null)
            return true;
        if((list1 == null && list2 != null) || (list1 != null && list2 == null))
            return false;

        if(list1.size()!=list2.size())
            return false;
        for(Object itemList1: list1)
        {
            if(!list2.contains(itemList1))
                return false;
        }

        return true;
    }
9
Traveling Salesman

Sur la définition de la "similitude"

Comme Joachim l'a noté, pour la plupart des applications, la définition List.equals(Object o) fonctionne:

Compare l'objet spécifié avec cette liste pour l'égalité. Renvoie true si et seulement si l'objet spécifié est également une liste, les deux listes ont la même taille et toutes les paires d'éléments correspondantes dans les deux listes sont égales. (Deux éléments e1 Et e2 Sont égaux si (e1==null ? e2==null : e1.equals(e2)).) En d'autres termes, deux listes sont définies pour être égales si elles contiennent les mêmes éléments dans le même ordre. Cette définition garantit que la méthode equals fonctionne correctement sur différentes implémentations de l'interface List.

Selon la façon dont vous l'utilisez, cependant, cela peut ne pas fonctionner comme prévu. Si vous avez un List<int[]>, Par exemple, cela ne fonctionne pas vraiment parce que les tableaux héritent equals de Object qui définit l'égalité comme identité de référence.

    List<int[]> list1 = Arrays.asList(new int[] { 1, 2, 3 });
    List<int[]> list2 = Arrays.asList(new int[] { 1, 2, 3 });
    System.out.println(list1.equals(list2)); // prints "false"

De plus, deux listes avec un paramètre de type différent peuvent être equals:

    List<Number> list1 = new ArrayList<Number>();
    List<String> list2 = new ArrayList<String>();
    System.out.println(list1.equals(list2)); // prints "true"

Vous avez également mentionné que la liste doit contenir des éléments du même type. Voici encore un autre exemple où les éléments n'ont pas le même type, et pourtant ils sont equals:

    List<Object> list1 = new ArrayList<Object>();
    List<Object> list2 = new ArrayList<Object>();
    list1.add(new ArrayList<Integer>());
    list2.add(new LinkedList<String>());
    System.out.println(list1.equals(list2)); // prints "true"

Donc, à moins que vous ne définissiez clairement ce que l'égalité signifie pour vous, la question peut avoir des réponses très différentes. Cependant, pour la plupart des applications pratiques, List.equals Devrait suffire.


Lors de l'implémentation de equals

Les informations après la mise à jour suggèrent que List.equals Fera très bien le travail, à condition que les éléments implémentent equals correctement (car List<E>.equals Invoque E.equals Sur les éléments nonnull-, selon la documentation de l'API ci-dessus).

Donc dans ce cas, si nous avons, disons, un List<Player>, Alors Player doit @Override equals(Object o) pour retourner true si o instanceof Player Et dans les champs appropriés, ils sont tous equals (pour les types de référence) ou == (pour les primitives).

Bien sûr, lorsque vous @Override equals, Vous devez également @Override int hashCode(). Le minimum à peine acceptable est de return 42;; un peu mieux est de return name.hashCode();; le mieux est d'utiliser une formule qui implique tous les champs sur lesquels vous définissez equals. Un bon IDE peut générer automatiquement des méthodes equals/hashCode Pour vous.

Voir également

  • En vigueur Java 2e édition
    • Point 8: Obéissez au contrat général lorsque vous remplacez égal
    • Élément 9: Toujours remplacer le code de hachage lorsque vous remplacez égal

Liens API

Questions connexes

Sur le combo equals/hashCode:

Sur equals vs ==:

79

Utilisez equals(). Tant que les éléments à l'intérieur des listes implémentent correctement equals(), ils renverront les valeurs correctes.

À moins que vous ne vouliez ignorer l'ordre des valeurs, vous devez alors vider les valeurs dans deux objets Set et les comparer à l'aide de equals().

12
Joachim Sauer

Comme @Joachim Sauer l'a mentionné dans sa réponse, equals devrait fonctionner si les listes sont égales et que leur contenu est correctement implémenté. Mais, cela ne devrait pas fonctionner si les éléments ne sont pas dans le même "ordre" car il n'utilise pas de contenu pour la vérification. En ce sens, il vérifie l'égalité "stricte" comme mentionné par @jarnbjo

        //From Android's Arraylist implementation
        Iterator<?> it = that.iterator();
        for (int i = 0; i < s; i++) {
            Object eThis = a[i];
            Object eThat = it.next();
            if (eThis == null ? eThat != null : !eThis.equals(eThat)) {
                return false;
            }
        }

Cependant, je voulais un comportement quelque peu différent, je me fichais de l'ordre ou de quelque chose comme ça. Tout ce que je voulais, c'était être sûr que les deux ne contenaient pas les mêmes éléments. Ma solution,

    //first check that both are not null and are of same length. (not shown here)
    //if both match, pull out the big guns as below
    ...
    List<Object> comparedList = new ArrayList<>(listOne);
    comparedList.removeAll(listTwo);
    if(comparedList.size() != 0) //there are differences between the two

C'est moins performant car il boucle deux fois, d'abord dans removeAll puis dans contains qui est appelé par removeAll.

Ma liste était garantie d'être courte, donc cela ne me dérangeait pas.

2
frostymarvelous

Vous pouvez les convertir en chaîne, puis comparer comme

list1.toString().equals(list2.toString())
2
Robert Londo