J'ai deux ArrayList
s de type Answer
(classe self-made).
J'aimerais comparer les deux listes pour voir si elles contiennent le même contenu, mais sans ordre d'importance.
Exemple:
//These should be equal.
ArrayList<String> listA = {"a", "b", "c"}
ArrayList<String> listB = {"b", "c", "a"}
List.equals
indique que deux listes sont égales si elles contiennent la même taille, le même contenu et l'ordre des éléments. Je veux la même chose, mais sans ordre d'importance.
Existe-t-il un moyen simple de procéder? Ou aurai-je besoin de faire une boucle for imbriquée et de vérifier manuellement chaque index des deux listes?
Remarque: je ne peux pas les changer ArrayList
pour un autre type de liste, ils doivent le rester.
Réponses:
Vous pouvez trier les deux listes en utilisant
Collections.sort()
, puis utiliser la méthode d'égalité. Une solution légèrement meilleure consiste à vérifier d'abord si elles ont la même longueur avant de commander, si elles ne le sont pas, alors elles ne sont pas égales, puis trier, puis utiliser égales. Par exemple, si vous aviez deux listes de chaînes, ce serait quelque chose comme:la source
Collections.sort
fait) - c'est-à-dire de transmettre une copie.one = new ArrayList<String>(one); two = new ArrayList<String>(two);
pour éviter de ruiner les arguments.if(one == null || two == null || one.size() != two.size()){ return false; }
car vous vérifiez déjà si un et deux sont nulsLe moyen le plus simple pour toute liste serait probablement:
la source
[a, b, c]
et[c, b, a, b]
sont considérés comme ayant le même contenu. Cette réponse dirait qu'ils le font, mais il se peut que pour l'OP ils ne le fassent pas (puisque l'un contient un doublon et l'autre pas). Pour ne rien dire des problèmes d'efficacité.Apache Commons Collections à la rescousse une fois de plus:
Documents:
la source
false
? Voyez ma réponse.implementation 'org.apache.commons:commons-collections4:4.3'
m'a laissé unCaused by: com.android.builder.dexing.DexArchiveBuilderException: Failed to process
chemin d' erreur .la source
count
devient négatif, ce qui simplifie le corps de laif(!counts.containsKey(item) || --counts.get(item).count < 0) return false;
boucle.En outre, la troisième boucle pourrait être simplifiée àfor(Count c: counts.values()) if(c.count != 0) return false;
counts
est vide"), mais je ne voulais pas obscurcir le point principal: que l'utilisation d'une carte transforme fondamentalement cela en un problème O (N + M), et c'est le plus gros coup de pouce que vous êtes susceptible d'obtenir.Map.merge
, l'utilisation d'entiers encadrés pourrait être plus simple et plus efficace pour la plupart des cas d'utilisation. Voir aussi cette réponse …Je dirais que ces réponses manquent un truc.
Bloch, dans son essentiel, merveilleux et concis Effective Java , dit, au point 47, titre «Connaître et utiliser les bibliothèques», «Pour résumer, ne réinventez pas la roue». Et il donne plusieurs raisons très claires pourquoi pas.
Il y a quelques réponses ici qui suggèrent des méthodes de
CollectionUtils
la bibliothèque Apache Commons Collections, mais aucune n'a repéré la manière la plus belle et la plus élégante de répondre à cette question :Les coupables : c'est-à-dire les éléments qui ne sont pas communs aux deux
Lists
. Déterminer à quels coupables appartiennentlist1
et à quilist2
est relativement simple en utilisantCollectionUtils.intersection( list1, culprits )
etCollectionUtils.intersection( list2, culprits )
.Cependant, il a tendance à s'effondrer dans des cas comme {"a", "a", "b"}
disjunction
avec {"a", "b", "b"} ... sauf que ce n'est pas un échec du logiciel, mais inhérente à la nature des subtilités / ambiguïtés de la tâche souhaitée.Vous pouvez toujours examiner le code source (l. 287) pour une tâche comme celle-ci, tel que produit par les ingénieurs Apache. Un avantage de l'utilisation de leur code est qu'il aura été minutieusement essayé et testé, avec de nombreux cas extrêmes et des pièges anticipés et traités. Vous pouvez copier et modifier ce code à votre guise si nécessaire.
NB J'ai été au début déçu qu'aucune des
CollectionUtils
méthodes ne propose une version surchargée vous permettant d'imposer la vôtreComparator
(afin que vous puissiez la redéfinirequals
en fonction de vos besoins).Mais à partir de collections4 4.0, il existe une nouvelle classe,
Equator
qui "détermine l'égalité entre les objets de type T". À l'examen du code source de collections4 CollectionUtils.java, ils semblent l'utiliser avec certaines méthodes, mais pour autant que je sache, cela ne s'applique pas aux méthodes en haut du fichier, en utilisant laCardinalityHelper
classe ... qui incluredisjunction
etintersection
.Je suppose que les gens d'Apache ne sont pas encore parvenus à cela parce que ce n'est pas trivial: vous devriez créer quelque chose comme une classe "AbstractEquatingCollection", qui au lieu d'utiliser les méthodes
equals
et les éléments inhérents à ses élémentshashCode
deEquator
pour toutes les méthodes de base, tels queadd
,contains
, etc. NB en fait , quand vous regardez le code source,AbstractCollection
ne met pas en oeuvreadd
, ni ne les sous - classes abstraites telles queAbstractSet
... vous devez attendre jusqu'à ce que les classes concrètes telles queHashSet
etArrayList
avantadd
est implémenté. Un mal de tête.En attendant, surveillez cet espace, je suppose. La solution provisoire évidente serait d'envelopper tous vos éléments dans une classe wrapper sur mesure qui utilise
equals
ethashCode
d'implémenter le type d'égalité que vous souhaitez ... puis de manipulerCollections
ces objets wrapper.la source
Si la cardinalité des éléments n'a pas d'importance (c'est-à-dire que les éléments répétés sont considérés comme un), il existe un moyen de le faire sans avoir à trier:
boolean result = new HashSet<>(listA).equals(new HashSet<>(listB));
Cela créera un
Set
hors de chacunList
, puis utiliseraHashSet
laequals
méthode de qui (bien sûr) ne tient pas compte de l'ordre.Si la cardinalité compte, vous devez vous limiter aux installations fournies par
List
; La réponse de @ jschoen serait plus appropriée dans ce cas.la source
La conversion des listes en Multiset de Guava fonctionne très bien. Ils sont comparés quel que soit leur ordre et les éléments en double sont également pris en compte.
la source
Ceci est basé sur la solution @cHao. J'ai inclus plusieurs correctifs et améliorations de performances. Cela fonctionne environ deux fois plus vite que la solution de copie ordonnée égale. Fonctionne pour tout type de collection. Les collections vides et nulles sont considérées comme égales. Utilisez à votre avantage;)
la source
false
lorsqu'une clé n'existe pas ou que son compte devient négatif. Étant donné que la taille totale des deux listes correspond (cela a été vérifié au départ), il est impossible d'avoir des valeurs non nulles après la deuxième boucle, car il ne peut pas y avoir de valeurs positives pour une clé sans valeurs négatives pour une autre clé.Pensez à la façon dont vous feriez cela vous-même, sans ordinateur ou langage de programmation. Je vous donne deux listes d'éléments, et vous devez me dire si elles contiennent les mêmes éléments. Comment feriez-vous cela?
Une approche, comme mentionné ci-dessus, consiste à trier les listes, puis à aller élément par élément pour voir si elles sont égales (ce qui
List.equals
cas). Cela signifie que vous êtes autorisé à modifier les listes ou que vous êtes autorisé à les copier - et sans connaître l'affectation, je ne peux pas savoir si l'une ou les deux sont autorisées.Une autre approche consisterait à parcourir chaque liste, en comptant le nombre de fois où chaque élément apparaît. Si les deux listes ont les mêmes nombres à la fin, elles ont les mêmes éléments. Le code pour cela serait de traduire chaque liste en une carte
elem -> (# of times the elem appears in the list)
, puis d'appelerequals
les deux cartes. Si les cartes le sontHashMap
, chacune de ces traductions est une opération O (N), tout comme la comparaison. Cela va vous donner un algorithme assez efficace en termes de temps, au prix d'un peu de mémoire supplémentaire.la source
J'ai eu le même problème et j'ai trouvé une solution différente. Celui-ci fonctionne également lorsque des doublons sont impliqués:
Avantages par rapport à certaines autres solutions:
[1,2,3,3]
et un autre tableau, la[1,2,2,3]
plupart des solutions ici vous indiquent qu'ils sont les mêmes si vous ne considérez pas l'ordre. Cette solution évite cela en supprimant les éléments égaux des listes temporaires;equals
) et non l'égalité de référence (==
);implement Comparable
) pour que cette solution fonctionne.la source
Si vous n'espérez pas trier les collections et que vous avez besoin du résultat que ["A" "B" "C"] n'est pas égal à ["B" "B" "A" "C"],
n'est pas suffisant, vous devez probablement vérifier la taille aussi:
la source
Solution qui exploite la méthode de soustraction de CollectionUtils:
la source
Si vous vous souciez de la commande, utilisez simplement la méthode égale:
Si vous ne vous souciez pas de la commande, utilisez ceci
la source
Le meilleur des deux mondes [@DiddiZ, @Chalkos]: celui-ci s'appuie principalement sur la méthode @Chalkos, mais corrige un bogue (ifst.next ()), améliore les vérifications initiales (tirées de @DiddiZ) et supprime le besoin de copier la première collection (supprime simplement les éléments d'une copie de la deuxième collection).
Ne nécessitant pas de fonction de hachage ou de tri, et permettant une existence précoce sur l'inégalité, c'est l'implémentation la plus efficace à ce jour. À moins que vous n'ayez une longueur de collection de plusieurs milliers ou plus, et une fonction de hachage très simple.
la source
C'est un moyen alternatif de vérifier l'égalité des listes de tableaux qui peuvent contenir des valeurs nulles:
la source
Ma solution pour cela. Ce n'est pas si cool, mais ça marche bien.
la source
Dans ce cas, les listes {"a", "b"} et {"b", "a"} sont égales. Et {"a", "b"} et {"b", "a", "c"} ne sont pas égaux. Si vous utilisez une liste d'objets complexes, n'oubliez pas de remplacer la méthode equals , car containsAll l' utilise à l'intérieur.
la source
AbstractCollection.containsAll()
. Vous devez permettre d'avoir des éléments en double dont nous parlonsLists
, pas deSets
. S'il vous plaît voir ma réponse.