wie finde ich Duplikate in std :: vectorstring und gebe eine Liste von ihnen zurück?

8

Wenn ich also einen Vektor mit Wörtern wie:

habe %Vor%

Ergebnisliste: "Spaß", "Wörter"

Ich versuche zu bestimmen, welche Wörter dupliziert werden, und gebe einen alphabetischen Vektor von 1 Kopie von ihnen zurück. Mein Problem ist, dass ich nicht einmal weiß, wo ich anfangen soll. Das einzige, was ich gefunden habe, war std::unique_copy , was nicht genau das tut, was ich brauche. Und zwar gebe ich ein std::vector<std::string> ein, gebe aber ein std::list<std::string> aus. Und wenn nötig, kann ich Funktor verwenden.

Könnte mich bitte jemand in die richtige Richtung drängen? Ich habe schon versucht, stl Dokumentation zu lesen, aber ich bin gerade "Gehirn" blockiert jetzt.

    
Marina Golubtsova 27.07.2013, 00:11
quelle

6 Antworten

5
  1. Machen Sie eine leere std::unordered_set<std::string>
  2. Iteriere deinen Vektor und überprüfe, ob jeder Gegenstand ein Mitglied der Menge ist
  3. Wenn es bereits in der Menge ist, ist dies ein Duplikat, also fügen Sie es zu Ihrer Ergebnisliste hinzu
  4. Andernfalls fügen Sie dem Set hinzu.

Da jedes Duplikat nur einmal in den Ergebnissen aufgeführt sein soll, können Sie auch ein Hashset (nicht Liste) für die Ergebnisse verwenden.

    
Ben Voigt 27.07.2013 00:32
quelle
5

IMO, Ben Voigt hat mit einer guten Grundidee angefangen, aber ich warne davor, seinen Wortlaut zu wörtlich zu nehmen.

Insbesondere mag ich nicht die Idee, nach der Zeichenfolge in der Menge zu suchen, sie dann zu Ihrer Menge hinzuzufügen, wenn sie nicht vorhanden ist, und sie der Ausgabe hinzuzufügen, wenn sie vorhanden ist. Das bedeutet im Grunde, dass jedes Mal, wenn wir auf ein neues Wort treffen, wir unsere bestehenden Wörter zweimal durchsuchen, um einmal zu prüfen, ob ein Wort vorhanden ist, und es erneut einzufügen, weil es nicht existiert. Der Großteil dieser Suche wird im Wesentlichen identisch sein - es sei denn, ein anderer Thread mutiert die Struktur in der Zwischenzeit (was eine Race-Bedingung ergeben könnte).

Stattdessen würde ich versuchen, es zu den Wörtern hinzuzufügen, die Sie gesehen haben. Das gibt pair<iterator, bool> zurück, wobei% code_% auf bool gesetzt wird, wenn und nur wenn der Wert eingefügt wurde - d. H. War vorher nicht vorhanden. Dadurch können wir die Suche nach einer vorhandenen Zeichenfolge und die Einfügung der neuen Zeichenfolge in einer einzigen Einfügung zusammenfassen:

%Vor%

Dies räumt auch den Fluss auf, so dass es ziemlich einfach ist, den Test zu einem Funktor zu machen, den wir dann mit true verwenden können, um unsere Ergebnisse direkt zu produzieren:

%Vor%

Je nachdem, ob mir die Code-Einfachheit oder die Ausführungsgeschwindigkeit am Herzen lag, verwende ich möglicherweise std::remove_copy_if anstelle von std::vector für das Ergebnis und verwende set gefolgt von std::sort , um das Endergebnis zu erzeugen. In einem solchen Fall würde ich wahrscheinlich auch die std::unique_copy innerhalb von std::set durch eine show_copies ersetzen:

%Vor%

Dies ist geringfügig komplexer (eine ganze Zeile länger!), aber wahrscheinlich wesentlich schneller, wenn / wenn die Anzahl der Wörter sehr groß wird. Beachten Sie auch, dass ich std::unordered_set hauptsächlich verwende, um sichtbare Ausgaben zu erzeugen. Wenn Sie das Ergebnis nur in einer Sammlung haben möchten, können Sie das standardmäßige Unique / Erase-Idiom verwenden, um eindeutige Elemente in std::unique_copy zu erhalten.

    
Jerry Coffin 27.07.2013 05:24
quelle
3

In 3 Zeilen (ohne die Vektor- und Listenerstellung oder die überflüssigen Zeilenumbrüche im Namen der Lesbarkeit):

%Vor%

BEARBEITEN

Erklärung der Lösung:

  1. Das Sortieren des Vektors wird benötigt, um später set_difference() zu verwenden.

  2. Der uvec satz wird Elemente automatisch sortiert halten und Dubletten eliminieren.

  3. Die output Liste wird mit den Elementen von vec - uvec gefüllt.

DanielKO 27.07.2013 08:19
quelle
1

An Ort und Stelle (kein zusätzlicher Speicher). Kein String-Kopieren (außer zur Ergebnisliste). Eine Sorte + ein Pass:

%Vor%     
Leonid Volnitsky 27.07.2013 08:50
quelle
0

Sie können eine ziemlich saubere Implementierung mit einer std :: map erhalten, um die Vorkommen zu zählen und sich dann auf std :: list :: sort zu verlassen, um die resultierende Liste von Wörtern zu sortieren. Zum Beispiel:

%Vor%

Mit einer std :: map scheint es ein wenig verschwenderisch zu sein, aber es erledigt den Job.

    
Ethan Kaminski 27.07.2013 00:25
quelle
0

Hier ist ein besserer Algorithmus als die, die andere Leute vorgeschlagen haben:

%Vor%

Es ist besser, weil es nur swap mit keinem zusätzlichen vector für den Speicher benötigt, was bedeutet, dass es sich für frühere Versionen von C ++ optimal verhält und keine Elemente kopierbar sein müssen.

Wenn Sie schlauer sind, denke ich, dass Sie vermeiden können, den Vektor doppelt so gut zu sortieren.

    
Mehrdad 27.07.2013 08:33
quelle

Tags und Links