Ich habe zwei ArrayList
s vom Typ Answer
(selbstgemachte Klasse).
Ich möchte die beiden Listen vergleichen, um festzustellen, ob sie denselben Inhalt enthalten, jedoch ohne dass die Reihenfolge von Bedeutung ist.
Beispiel:
//These should be equal.
ArrayList<String> listA = {"a", "b", "c"}
ArrayList<String> listB = {"b", "c", "a"}
List.equals
gibt an, dass zwei Listen gleich sind, wenn sie dieselbe Größe, denselben Inhalt und dieselbe Reihenfolge von Elementen enthalten. Ich möchte das Gleiche, aber ohne dass die Reihenfolge von Bedeutung ist.
Gibt es eine einfache Möglichkeit, dies zu tun? Oder muss ich eine verschachtelte for-Schleife erstellen und jeden Index beider Listen manuell überprüfen?
Hinweis: Ich kann sie nicht von ArrayList
einem anderen Listentyp ändern , das müssen sie bleiben.
Antworten:
Sie können beide Listen mit
Collections.sort()
der Methode equals sortieren und dann verwenden. Eine etwas bessere Lösung besteht darin, vor der Bestellung zu überprüfen, ob sie gleich lang sind. Wenn dies nicht der Fall ist, sind sie nicht gleich, sortieren und verwenden dann gleich. Wenn Sie beispielsweise zwei Listen mit Zeichenfolgen hätten, wäre dies ungefähr so:quelle
Collections.sort
Fall ist) - dh eine Kopie zu übergeben.one = new ArrayList<String>(one); two = new ArrayList<String>(two);
, um die Argumente nicht zu ruinieren.if(one == null || two == null || one.size() != two.size()){ return false; }
da Sie bereits prüfen, ob sowohl eins als auch zwei null sindDer wahrscheinlich einfachste Weg für eine Liste wäre:
quelle
[a, b, c]
und ob[c, b, a, b]
derselbe Inhalt vorliegt. Diese Antwort würde sagen, dass sie es tun, aber es könnte sein, dass sie es für das OP nicht tun (da eines ein Duplikat enthält und das andere nicht). Ganz zu schweigen von den Effizienzproblemen.Apache Commons Sammlungen zur Rettung noch einmal:
Docs:
quelle
false
? Siehe meine Antwort.implementation 'org.apache.commons:commons-collections4:4.3'
habe mich mit einem Fehler linkenCaused by: com.android.builder.dexing.DexArchiveBuilderException: Failed to process
Pfad .quelle
count
negativ wird, was den Schleifenkörper vereinfacht.if(!counts.containsKey(item) || --counts.get(item).count < 0) return false;
Außerdem könnte die dritte Schleife vereinfacht werdenfor(Count c: counts.values()) if(c.count != 0) return false;
counts
leer" umwandelt), wollte aber nicht verschleiern Der Hauptpunkt: Die Verwendung einer Karte macht dies im Grunde genommen zu einem O (N + M) -Problem und ist der größte Einzelschub, den Sie wahrscheinlich bekommen werden.Map.merge
Ganzzahlen in den meisten Anwendungsfällen einfacher und effizienter sein kann. Siehe auch diese Antwort …Ich würde sagen, diese Antworten verpassen einen Trick.
Bloch sagt in seinem wesentlichen, wunderbaren, prägnanten, effektiven Java in Punkt 47, Titel "Die Bibliotheken kennen und benutzen", "Zusammenfassend, erfinden Sie das Rad nicht neu". Und er gibt mehrere sehr klare Gründe an, warum nicht.
Hier gibt es einige Antworten, die Methoden aus
CollectionUtils
der Apache Commons Collections-Bibliothek vorschlagen, aber keine hat die schönste und eleganteste Art gefunden, diese Frage zu beantworten :Schuldige : dh die Elemente, die beiden nicht gemeinsam sind
Lists
. Die Festlegung , welche Schuldigen gehörenlist1
und die zulist2
relativ einfach verwendetCollectionUtils.intersection( list1, culprits )
undCollectionUtils.intersection( list2, culprits )
.In Fällen wie {"a", "a", "b"} neigt es jedoch dazu, auseinanderzufallen.
disjunction
mit {"a", "b", "b"} auseinanderzufallen ... außer dies ist kein Fehler der Software, aber der Art der Feinheiten / Mehrdeutigkeiten der gewünschten Aufgabe inhärent.Sie können den Quellcode (l. 287) jederzeit auf eine solche Aufgabe untersuchen, wie sie von den Apache-Ingenieuren erstellt wurde. Ein Vorteil der Verwendung ihres Codes besteht darin, dass er gründlich erprobt und getestet wurde und viele Randfälle und Fallstricke vorweggenommen und behandelt wurden. Sie können diesen Code bei Bedarf nach Herzenslust kopieren und optimieren.
NB Ich war zunächst enttäuscht, dass keine der
CollectionUtils
Methoden eine überladene Version bietet, mit der Sie Ihre eigene auferlegen könnenComparator
(damit Sie sieequals
für Ihre Zwecke neu definieren können ).Aus Sammlungen4 4.0 gibt es jedoch eine neue Klasse,
Equator
die "die Gleichheit zwischen Objekten vom Typ T bestimmt". Bei der Prüfung des Quellcodes von collection4 CollectionUtils.java scheinen sie dies mit einigen Methoden zu verwenden, aber soweit ich das beurteilen kann, gilt dies nicht für die Methoden oben in der Datei, die dieCardinalityHelper
Klasse ... verwenden umfassendisjunction
undintersection
.Ich vermute, dass die Apache-Leute noch nicht dazu gekommen sind, weil es nicht trivial ist: Sie müssten so etwas wie eine "AbstractEquatingCollection" -Klasse erstellen, die anstelle der inhärenten
equals
undhashCode
Methoden ihrer Elemente diese verwenden müsste derEquator
für alle grundlegenden Methoden, wie zum Beispieladd
,contains
usw. NB in der Tat , wenn Sie auf den Quellcode schauen,AbstractCollection
nicht implementiertadd
, noch seine abstrakte Subklassen wieAbstractSet
... Sie bis in die konkreten Klassen wie wartenHashSet
undArrayList
voradd
ist implementiert. Ziemlich Kopfschmerzen.In der Zwischenzeit diesen Raum beobachten, nehme ich an. Die naheliegende Zwischenlösung wäre, alle Ihre Elemente in eine maßgeschneiderte Wrapper-Klasse zu verpacken , die die gewünschte Gleichheit verwendet
equals
undhashCode
implementiert ... und dannCollections
diese Wrapper-Objekte zu manipulieren .quelle
Wenn die Kardinalität von Elementen keine Rolle spielt (dh wiederholte Elemente werden als eins betrachtet), gibt es eine Möglichkeit, dies zu tun, ohne sortieren zu müssen:
boolean result = new HashSet<>(listA).equals(new HashSet<>(listB));
Dadurch wird
Set
aus jedem ein Out erstelltList
und dann verwendetHashSet
‚sequals
Methode , die (natürlich) missachtet Ordnung.Wenn Kardinalität wichtig ist, müssen Sie sich auf Einrichtungen beschränken, die von bereitgestellt werden
List
; @ jschoens Antwort wäre in diesem Fall passender.quelle
Das Konvertieren der Listen in Guavas Multiset funktioniert sehr gut. Sie werden unabhängig von ihrer Reihenfolge verglichen und doppelte Elemente werden ebenfalls berücksichtigt.
quelle
Dies basiert auf der @ cHao-Lösung. Ich habe mehrere Korrekturen und Leistungsverbesserungen hinzugefügt. Dies läuft ungefähr doppelt so schnell wie die Lösung für gleich geordnete Kopien. Funktioniert für jeden Sammlungstyp. Leere Sammlungen und Null werden als gleich angesehen. Nutzen Sie zu Ihrem Vorteil;)
quelle
false
wenn ein Schlüssel nicht vorhanden ist oder seine Anzahl negativ wird. Da die Gesamtgröße beider Listen übereinstimmt (dies wurde im Voraus überprüft), ist es unmöglich, nach der zweiten Schleife Werte ungleich Null zu haben, da es für einen Schlüssel keine positiven Werte ohne negative Werte für einen anderen Schlüssel geben kann.Überlegen Sie, wie Sie dies selbst tun würden, wenn Sie keinen Computer oder keine Programmiersprache hätten. Ich gebe Ihnen zwei Listen von Elementen, und Sie müssen mir sagen, ob sie die gleichen Elemente enthalten. Wie würdest du es machen?
Wie oben erwähnt, besteht ein Ansatz darin, die Listen zu sortieren und dann Element für Element zu prüfen, ob sie gleich sind (was auch der
List.equals
Fall ist). Dies bedeutet, dass Sie entweder die Listen ändern oder kopieren dürfen - und ohne die Zuordnung zu kennen, kann ich nicht wissen, ob eine oder beide zulässig sind.Ein anderer Ansatz wäre, jede Liste durchzugehen und zu zählen, wie oft jedes Element erscheint. Wenn beide Listen am Ende die gleiche Anzahl haben, haben sie die gleichen Elemente. Der Code dafür wäre, jede Liste in eine Karte von zu übersetzen
elem -> (# of times the elem appears in the list)
und dannequals
die beiden Karten aufzurufen . Wenn die Karten sindHashMap
, ist jede dieser Übersetzungen eine O (N) -Operation, ebenso wie der Vergleich. Das gibt Ihnen einen ziemlich effizienten Algorithmus in Bezug auf die Zeit auf Kosten von zusätzlichem Speicher.quelle
Ich hatte das gleiche Problem und fand eine andere Lösung. Dieser funktioniert auch, wenn Duplikate beteiligt sind:
Vorteile gegenüber einigen anderen Lösungen:
[1,2,3,3]
und ein anderes Array[1,2,2,3]
haben, sagen Ihnen die meisten Lösungen hier, dass sie gleich sind, wenn Sie die Reihenfolge nicht berücksichtigen. Diese Lösung vermeidet dies, indem gleiche Elemente aus den temporären Listen entfernt werden.equals
) und nicht Referenzgleichheit (==
);implement Comparable
diese Lösung funktioniert.quelle
Wenn Sie nicht hoffen, die Sammlungen zu sortieren, und Sie das Ergebnis benötigen, dass ["A" "B" "C"] nicht gleich ["B" "B" "A" "C"] ist,
ist nicht genug, Sie müssen wahrscheinlich auch die Größe überprüfen:
quelle
Lösung, die die Subtraktionsmethode CollectionUtils nutzt:
quelle
Wenn Sie sich für die Bestellung interessieren, verwenden Sie einfach die Methode equals:
Wenn es Ihnen egal ist, bestellen Sie diese
quelle
Das Beste aus beiden Welten [@DiddiZ, @Chalkos]: Diese basiert hauptsächlich auf der @ Chalkos-Methode, behebt jedoch einen Fehler (ifst.next ()) und verbessert die anfänglichen Überprüfungen (aus @DiddiZ) sowie die Notwendigkeit Kopieren Sie die erste Sammlung (entfernt nur Elemente aus einer Kopie der zweiten Sammlung).
Dies ist die bisher effizienteste Implementierung, die keine Hashing-Funktion oder Sortierung erfordert und eine frühzeitige Existenz bei Ungleichheit ermöglicht. Es sei denn, Sie haben eine Sammlungslänge von Tausenden oder mehr und eine sehr einfache Hashing-Funktion.
quelle
Es ist eine alternative Möglichkeit, die Gleichheit von Array-Listen zu überprüfen, die Nullwerte enthalten können:
quelle
Meine Lösung dafür. Es ist nicht so cool, funktioniert aber gut.
quelle
In diesem Fall sind die Listen {"a", "b"} und {"b", "a"} gleich. Und {"a", "b"} und {"b", "a", "c"} sind nicht gleich. Wenn Sie die Liste von komplexen Objekten verwenden, denken Sie daran, Überschreibung gleich Methode, wie containsAll es im Inneren verwendet.
quelle
AbstractCollection.containsAll()
. Sie müssen zulassen, dass doppelte Elemente vorhanden sind, über die wir sprechenLists
, nicht überSets
. Bitte sehen Sie meine Antwort.