Ich versuche, einen Code zu optimieren, der Elemente der Liste vergleicht.
Z.B.
public void compare(Set<Record> firstSet, Set<Record> secondSet){
for(Record firstRecord : firstSet){
for(Record secondRecord : secondSet){
// comparing logic
}
}
}
Bitte beachten Sie, dass die Anzahl der Datensätze in Sätzen hoch ist.
Vielen Dank
Shekhar
java
performance
set
Shekhar
quelle
quelle
Antworten:
Es hängt wirklich davon ab, was Sie in der Vergleichslogik tun möchten ... dh was passiert, wenn Sie ein Element in einer Menge finden, nicht in der anderen? Ihre Methode hat einen
void
Rückgabetyp, daher gehe ich davon aus, dass Sie die erforderliche Arbeit in dieser Methode ausführen werden.Feinkörnigere Steuerung, wenn Sie sie benötigen:
Wenn Sie die Elemente benötigen, die sich in einem Satz befinden und nicht im anderen.
BEARBEITEN:
set.removeAll(otherSet)
Gibt einen Booleschen Wert zurück, keinen Satz. Um removeAll () zu verwenden, müssen Sie das Set kopieren und dann verwenden.Wenn der Inhalt von
one
undtwo
beide leer sind, wissen Sie, dass die beiden Sätze gleich waren. Wenn nicht, dann haben Sie die Elemente, die die Mengen ungleich gemacht haben.Sie haben erwähnt, dass die Anzahl der Datensätze möglicherweise hoch ist. Wenn es sich bei der zugrunde liegenden Implementierung um eine
HashSet
handelt, erfolgt das Abrufen jedes DatensatzesO(1)
rechtzeitig, sodass Sie nicht viel besser werden können.TreeSet
istO(log n)
.quelle
equals
schneller als zwei AufrufecontainsAll
. siehe meine Antwort.Wenn Sie einfach nur wissen möchten, ob die Mengen gleich sind, wird die
equals
Methode onAbstractSet
ungefähr wie folgt implementiert:Beachten Sie, wie die häufigsten Fälle optimiert werden, in denen:
Danach
containsAll(...)
wird zurückgegebenfalse
, sobald ein Element in der anderen Gruppe gefunden wird, das sich nicht ebenfalls in dieser Gruppe befindet. Wenn jedoch alle Elemente in beiden Sätzen vorhanden sind, müssen alle getestet werden.Die Worst-Case-Leistung tritt daher auf, wenn die beiden Sätze gleich, aber nicht dieselben Objekte sind. Diese Kosten sind in der Regel
O(N)
oderO(NlogN)
abhängig von der Implementierung vonthis.containsAll(c)
.Und Sie erhalten eine nahezu Worst-Case-Leistung, wenn die Sets groß sind und sich nur in einem winzigen Prozentsatz der Elemente unterscheiden.
AKTUALISIEREN
Wenn Sie bereit sind, Zeit in eine benutzerdefinierte Set-Implementierung zu investieren, gibt es einen Ansatz, der den "fast gleichen" Fall verbessern kann.
Die Idee ist, dass Sie einen Hash für den gesamten Satz vorberechnen und zwischenspeichern müssen, damit Sie den aktuellen Hashcode-Wert des Satzes erhalten
O(1)
. Dann können Sie den Hashcode für die beiden Sätze als Beschleunigung vergleichen.Wie könnten Sie einen solchen Hashcode implementieren? Nun, wenn der eingestellte Hashcode war:
Dann können Sie den zwischengespeicherten Hashcode des Sets jedes Mal, wenn Sie ein Element hinzufügen oder entfernen, kostengünstig aktualisieren. In beiden Fällen XOR Sie einfach den Hashcode des Elements mit dem aktuell eingestellten Hashcode.
Dies setzt natürlich voraus, dass Element-Hashcodes stabil sind, während die Elemente Mitglieder von Mengen sind. Es wird auch davon ausgegangen, dass die Hashcode-Funktion der Elementklassen eine gute Streuung ergibt. Dies liegt daran, dass Sie bei gleichen zwei gesetzten Hashcodes immer noch auf den
O(N)
Vergleich aller Elemente zurückgreifen müssen .Sie könnten diese Idee etwas weiter führen ... zumindest theoretisch.
WARNUNG - Dies ist sehr spekulativ. Ein "Gedankenexperiment", wenn Sie möchten.
Angenommen, Ihre Set-Element-Klasse verfügt über eine Methode zum Zurückgeben von Krypto-Prüfsummen für das Element. Implementieren Sie nun die Prüfsummen der Menge, indem Sie die für die Elemente zurückgegebenen Prüfsummen XOR-verknüpfen.
Was kauft uns das?
Wenn wir davon ausgehen, dass nichts hinter uns liegt, beträgt die Wahrscheinlichkeit, dass zwei ungleiche Mengenelemente die gleichen N-Bit-Prüfsummen haben, 2 -N . Und die Wahrscheinlichkeit, dass 2 ungleiche Mengen die gleichen N-Bit-Prüfsummen haben, beträgt ebenfalls 2 -N . Meine Idee ist also, dass Sie Folgendes implementieren können
equals
:Unter den oben genannten Annahmen erhalten Sie nur einmal in 2- N- Zeit die falsche Antwort . Wenn Sie N groß genug machen (z. B. 512 Bit), wird die Wahrscheinlichkeit einer falschen Antwort vernachlässigbar (z. B. ungefähr 10-150 ).
Der Nachteil ist, dass die Berechnung der Krypto-Prüfsummen für Elemente sehr teuer ist, insbesondere wenn die Anzahl der Bits zunimmt. Sie brauchen also wirklich einen effektiven Mechanismus zum Speichern der Prüfsummen. Und das könnte problematisch sein.
Und der andere Nachteil ist, dass eine Fehlerwahrscheinlichkeit ungleich Null inakzeptabel sein kann, egal wie gering die Wahrscheinlichkeit ist. (Aber wenn das der Fall ist ... wie gehen Sie mit dem Fall um, in dem ein kosmischer Strahl ein kritisches Bit umdreht? Oder wenn er in zwei Fällen eines redundanten Systems gleichzeitig dasselbe Bit umdreht?)
quelle
In Guave gibt es eine Methode,
Sets
die hier helfen kann:quelle
Sie haben die folgende Lösung von https://www.mkyong.com/java/java-how-to-compare-two-sets/
Oder wenn Sie eine einzelne return-Anweisung bevorzugen:
quelle
equals()
Methode vonAbstractSet
(im Lieferumfang von JDK enthalten), die bis auf die zusätzlichen Nullprüfungen fast der Lösung hier entspricht . Java-11 Set InterfaceEs gibt eine O (N) -Lösung für ganz bestimmte Fälle, in denen:
Der folgende Code setzt voraus, dass beide Sätze auf den vergleichbaren Datensätzen basieren. Eine ähnliche Methode könnte auf einem Komparator basieren.
quelle
Wenn Sie eine
Guava
Bibliothek verwenden, ist Folgendes möglich:Und dann daraus eine Schlussfolgerung ziehen.
quelle
Ich würde das secondSet vor dem Vergleich in eine HashMap einfügen. Auf diese Weise reduzieren Sie die Suchzeit der zweiten Liste auf n (1). So was:
quelle
quelle
Ich denke, dass eine Methodenreferenz mit der Methode gleich verwendet werden kann. Wir gehen davon aus, dass der Objekttyp zweifelsfrei eine eigene Vergleichsmethode hat. Ein einfaches Beispiel ist hier,
quelle
set.equals(set2)