arr
ist ein Array von Zeichenfolgen:
["hello", "world", "stack", "overflow", "hello", "again"]
Was wäre eine einfache und elegante Möglichkeit, um zu überprüfen, ob arr
Duplikate vorhanden sind, und wenn ja, eines davon zurückzugeben (egal welches)?
Beispiele:
["A", "B", "C", "B", "A"] # => "A" or "B"
["A", "B", "C"] # => nil
arr == arr.uniq
Dies wäre eine einfache und elegante Methode, um zu überprüfen, obarr
Duplikate vorhanden sind. Es werden jedoch keine Duplikate bereitgestellt.Antworten:
Ich weiß, dass dies keine sehr elegante Antwort ist, aber ich liebe es. Es ist wunderschön einzeiliger Code. Und funktioniert einwandfrei, es sei denn, Sie müssen große Datenmengen verarbeiten.
Suchen Sie nach einer schnelleren Lösung? Bitte schön!
Es ist linear, O (n), muss aber jetzt mehrere Codezeilen verwalten, benötigt Testfälle usw.
Wenn Sie eine noch schnellere Lösung benötigen, versuchen Sie es stattdessen mit C.
Und hier ist der Kern, der verschiedene Lösungen vergleicht: https://gist.github.com/naveed-ahmad/8f0b926ffccf5fbd206a1cc58ce9743e
quelle
a.select {|e| a.count(e) > 1}.uniq
Sie können dies auf verschiedene Arten tun, wobei die erste Option die schnellste ist:
Und eine O (N ^ 2) -Option (dh weniger effizient):
quelle
group_by.select
ary.group_by(&:itself)
. :-)Suchen Sie einfach die erste Instanz, in der der Index des Objekts (von links gezählt) nicht dem Index des Objekts entspricht (von rechts zählen).
Wenn keine Duplikate vorhanden sind, ist der Rückgabewert Null.
Ich glaube, dies ist auch die schnellste Lösung, die bisher im Thread veröffentlicht wurde, da sie nicht auf der Erstellung zusätzlicher Objekte beruht
#index
und#rindex
in C implementiert ist. Die Big-O-Laufzeit ist N ^ 2 und daher langsamer als Sergios, aber die Wandzeit könnte viel schneller sein, da die "langsamen" Teile in C laufen.quelle
arr.find_all {|e| arr.rindex(e) != arr.index(e) }.uniq
arr.detect.with_index { |e, idx| idx != arr.rindex(e) }
. Die Verwendungwith_index
sollte die Notwendigkeit für die ersteindex
Suche beseitigen .detect
findet nur ein Duplikat.find_all
wird sie alle finden:quelle
count
für jedes Element im Array aufzurufen . (Ein Zähl-Hash ist zum Beispiel viel effizienter; z . B.h = {"A"=>2, "B"=>2, "C"=> 1 }
dann konstruierenh.select { |k,v| v > 1 }.keys #=> ["A", "B"]
.Hier sind zwei weitere Möglichkeiten, ein Duplikat zu finden.
Verwenden Sie ein Set
Verwenden Sie
select
anstelle vonfind
, um ein Array aller Duplikate zurückzugeben.Verwenden
Array#difference
Löschen
.first
, um ein Array aller Duplikate zurückzugeben.Beide Methoden werden zurückgegeben,
nil
wenn keine Duplikate vorhanden sind.Ich schlug vor,
Array#difference
das dem Ruby-Kern hinzuzufügen. Weitere Informationen finden Sie in meiner Antwort hier .Benchmark
Vergleichen wir die vorgeschlagenen Methoden. Zunächst benötigen wir ein Array zum Testen:
und eine Methode zum Ausführen der Benchmarks für verschiedene Testarrays:
Ich habe die Antwort von @ JjP nicht aufgenommen, da nur ein Duplikat zurückgegeben werden soll. Wenn seine Antwort geändert wird, entspricht dies der früheren Antwort von @ Naveed. Ich habe auch nicht die Antwort von @ Marin aufgenommen, die, obwohl sie vor der Antwort von @ Naveed veröffentlicht wurde, alle Duplikate und nicht nur eines zurückgegeben hat (ein kleiner Punkt, aber es macht keinen Sinn, beide zu bewerten, da sie identisch sind, wenn nur ein Duplikat zurückgegeben wird).
Ich habe auch andere Antworten geändert, bei denen alle Duplikate zurückgegeben wurden, um nur die zuerst gefundenen zurückzugeben. Dies sollte jedoch im Wesentlichen keine Auswirkungen auf die Leistung haben, da alle Duplikate vor der Auswahl eines Duplikats berechnet wurden.
Die Ergebnisse für jeden Benchmark sind vom schnellsten zum langsamsten aufgeführt:
Angenommen, das Array enthält 100 Elemente:
Betrachten Sie nun ein Array mit 10.000 Elementen:
Beachten Sie, dass
find_a_dup_using_difference(arr)
dies viel effizienter wäre, wennArray#difference
es in C implementiert würde, was der Fall wäre, wenn es dem Ruby-Kern hinzugefügt würde.Fazit
Viele der Antworten sind vernünftig, aber die Verwendung eines Sets ist die eindeutig beste Wahl . Es ist am schnellsten in mittelschweren Fällen, am schnellsten in den schwierigsten Fällen und nur in rechnerisch trivialen Fällen - wenn Ihre Wahl sowieso keine Rolle spielt - kann es geschlagen werden.
Der ganz besondere Fall, in dem Sie sich für die Lösung von Chris entscheiden könnten, wäre, wenn Sie die Methode verwenden möchten, um Tausende kleiner Arrays separat zu de-duplizieren und ein Duplikat zu finden, das normalerweise weniger als 10 Elemente enthält. Dies ist etwas schneller Dies vermeidet den geringen zusätzlichen Aufwand beim Erstellen des Sets.
quelle
Leider sind die meisten Antworten
O(n^2)
.Hier ist eine
O(n)
Lösung,Was ist die Komplexität davon?
O(n)
und bricht beim ersten Spiel abO(n)
Speicher, aber nur die minimale MengeAbhängig davon, wie häufig Duplikate in Ihrem Array vorhanden sind, werden diese Laufzeiten möglicherweise sogar noch besser. Wenn das Größenarray beispielsweise
O(n)
aus einer Populationk << n
verschiedener Elemente abgetastet wurde, wird nur die Komplexität sowohl für die Laufzeit als auch für den Speicherplatz.O(k)
Es ist jedoch wahrscheinlicher, dass das Originalposter die Eingabe validiert und sicherstellen möchte, dass keine Duplikate vorhanden sind. In diesem Fall sind sowohl die Laufzeit als auch die Speicherkomplexität zuO(n)
erwarten, da die Elemente für die meisten Eingaben keine Wiederholungen aufweisen.quelle
Ruby Array-Objekte haben eine großartige Methode
select
.Die erste Form interessiert Sie hier. Hier können Sie Objekte auswählen, die einen Test bestehen.
Ruby Array-Objekte haben eine andere Methode
count
.In diesem Fall interessieren Sie sich für Duplikate (Objekte, die mehr als einmal im Array vorkommen). Der entsprechende Test ist
a.count(obj) > 1
.Wenn ja
a = ["A", "B", "C", "B", "A"]
, dannSie geben an, dass Sie nur ein Objekt möchten . Wählen Sie also eine aus.
quelle
["A", "B", "B", "A"]
.uniq
auf ein Array zu setzen .count
für jedes Element des Arrays auf, was verschwenderisch und unnötig ist. Siehe meinen Kommentar zur Antwort von JjP.find_all () gibt ein zurück,
array
das alle Elemente enthält,enum
für die diesblock
nicht der Fall istfalse
.Um
duplicate
ElementeOder doppelte
uniq
Elementequelle
So etwas wird funktionieren
Das heißt, setzen Sie alle Werte in einen Hash, wobei key das Element des Arrays und value die Anzahl der Vorkommen ist. Wählen Sie dann alle Elemente aus, die mehrmals vorkommen. Einfach.
quelle
Ich weiß, dass es in diesem Thread speziell um Ruby geht, aber ich bin hier gelandet und habe nach einer Möglichkeit gesucht, dies im Kontext von Ruby on Rails mit ActiveRecord zu tun, und dachte, ich würde auch meine Lösung teilen.
Das Obige gibt ein Array aller E-Mail-Adressen zurück, die in der Datenbanktabelle dieses Beispiels dupliziert sind (in Rails wäre dies "active_record_classes").
quelle
Dies ist eine
O(n)
Prozedur.Alternativ können Sie eine der folgenden Zeilen ausführen. Auch O (n) aber nur eine Iteration
quelle
Hier ist meine Sicht auf einen großen Datensatz - wie eine ältere dBase-Tabelle, um doppelte Teile zu finden
quelle
quelle
each_with_object
ist dein Freund!quelle
Dieser Code gibt eine Liste doppelter Werte zurück. Hash-Schlüssel werden verwendet, um effizient zu überprüfen, welche Werte bereits gesehen wurden. Basierend darauf, ob ein Wert gesehen wurde, wird das ursprüngliche Array
ary
in zwei Arrays aufgeteilt: das erste enthält eindeutige Werte und das zweite enthält Duplikate.Sie können es weiter verkürzen - wenn auch auf Kosten einer etwas komplexeren Syntax - auf diese Form:
quelle
Ergebnisse
quelle
Wenn Sie zwei verschiedene Arrays vergleichen (anstatt eines mit sich selbst), können Sie sehr schnell den
&
von der Ruby-Array-Klasse bereitgestellten Schnittoperator verwenden .quelle
Ich musste herausfinden, wie viele Duplikate es gab und was sie waren, also schrieb ich eine Funktion, die auf dem aufbaute, was Naveed zuvor gepostet hatte:
quelle
Lassen Sie uns in der Code-Implementierung demonstrieren
Rufen Sie nun die Duplizierungsmethode auf und geben Sie das Ergebnis zurück -
quelle
[1,2,3].uniq!.nil? => true
[1,2,3,3].uniq!.nil? => false
Beachten Sie, dass das oben Genannte destruktiv ist
quelle