Comment comparer l’égalité des listes de tableaux avec Java moderne?

J’ai deux listes de tableaux.

Comment puis-je comparer facilement leur égalité avec Java 8 et ses fonctionnalités , sans utiliser de bibliothèques externes? Je cherche une solution “meilleure” (niveau supérieur, plus court, plus efficace) que le code brute comme celui-ci (code non testé, peut contenir des fautes de frappe, etc., pas le but de la question):

boolean compare(List list1, List list2) { // tests for nulls etc omitted if(list1.size() != list2.size()) { return false; } for(i=0; i<list1.size(); ++i) { if(!Arrays.equals(list1.get(i), list2.get(i))) { return false; } } return true; } 

Ou, s’il n’y a pas de meilleur moyen, c’est une réponse valable aussi.

Bonus: Si Java 9 offre une solution encore meilleure à ce que Java 8 peut offrir, n’hésitez pas à le mentionner également.

Edit: Après avoir regardé les commentaires, et vu comment cette question est devenue modérément chaude, je pense que le ” meilleur ” devrait d’abord vérifier les longueurs de tous les tableaux, avant de vérifier le contenu des tableaux , car les tableaux sont longs.

1) Solution basée sur les stream Java 8:

 List> first = list1.stream().map(Arrays::asList).collect(toList()); List> second = list2.stream().map(Arrays::asList).collect(toList()); return first.equals(second); 

2) Solution beaucoup plus simple (fonctionne avec Java 5+):

 return Arrays.deepEquals(list1.toArray(), list2.toArray()); 

3) En ce qui concerne votre nouvelle exigence (pour vérifier d’abord la longueur des tableaux Ssortingng), vous pouvez écrire une méthode d’assistance générique qui vérifie l’égalité pour les listes transformées:

  boolean equal(List list1, List list2, Function mapper) { List first = list1.stream().map(mapper).collect(toList()); List second = list2.stream().map(mapper).collect(toList()); return first.equals(second); } 

Alors la solution pourrait être:

 return equal(list1, list2, s -> s.length) && equal(list1, list2, Arrays::asList); 

La boucle for au moins peut être rationalisée, conduisant à:

 return (list1.size()==list2.size() && IntStream.range(0, list1.size()) .allMatch(i -> Arrays.equals(list1.get(i), list2.get(i))); 

en utilisant la fonction zip (qui provient de lambda b93) de https://stackoverflow.com/a/23529010/755183 , le code pourrait ressembler à ceci:

 boolean match = a.size() == b.size() && zip(a.stream(), b.stream(), Arrays::deepEquals). allMatch(equal -> equal) 

mettre à jour

afin de vérifier la taille des tableaux d’abord et puis contenu cela pourrait être une solution à considérer

 final boolean match = a.size() == b.size() && zip(a.stream(), b.stream(), (as, bs) -> as.length == bs.length). allMatch(equal -> equal) && zip(a.stream(), b.stream(), Arrays::deepEquals). allMatch(equal -> equal); 

Vous pouvez utiliser un stream si les listes sont des listes d’access aléatoires (de sorte qu’un appel soit rapide, généralement à temps constant), ce qui entraîne:

 //checks for null and size before boolean same = IntStream.range(0, list1.size()).allMatch(i -> Arrays.equals(list1.get(i), list2.get(i))); 

Cependant, vous pourriez donner comme parameters des implémentations qui ne le sont pas (comme LinkedLists). Dans ce cas, le meilleur moyen est d’utiliser explicitement l’iterator. Quelque chose comme:

 boolean compare(List list1, List list2) { //checks for null and size Iterator iteList1 = list1.iterator(); Iterator iteList2 = list2.iterator(); while(iteList1.hasNext()) { if(!Arrays.equals(iteList1.next(), iteList2.next())) { return false; } } return true; } 

Vous pouvez diffuser sur une liste et comparer à chaque élément de l’autre en utilisant un iterator:

 Iterator it = list1.iterator(); boolean match = list1.size() == list2.size() && list2.stream().allMatch(a -> Arrays.equals(a, it.next())); 

Utiliser un iterator au lieu de la méthode get(index) sur la première liste est préférable car il importe peu que la liste soit RandomAccess ou non.

Remarque: cela ne fonctionne qu’avec un stream séquentiel . L’utilisation d’un stream parallèle entraînera des résultats erronés.


EDIT: Selon la dernière édition de la question, qui indique qu’il serait préférable de vérifier la longueur de chaque paire de tableaux à l’avance , je pense que cela pourrait être réalisé avec une légère modification de mon code précédent:

 Iterator itLength = list1.iterator(); Iterator itContents = list1.iterator(); boolean match = list1.size() == list2.size() && list2.stream() .allMatch(a -> { Ssortingng[] s = itLength.next(); return s == null ? a == null : a == null ? s == null : a.length == s.length; }) && list2.stream() .allMatch(a -> Arrays.equals(a, itContents.next())); 

Ici, j’utilise deux iterators et je suis en streaming list2 deux fois, mais je ne vois aucun autre moyen de vérifier toutes les longueurs avant de vérifier le contenu de la première paire de tableaux. La vérification des longueurs est null-safe, tandis que la vérification du contenu est déléguée à la Arrays.equals(array1, array2) .