C ++ lambdas für std :: sort und std :: lower_bound / equal_range für ein Strukturelement in einem sortierten Vektor von Strukturen

8

Ich habe einen std :: vector dieser Struktur:

%Vor%

Ich möchte sowohl std :: sort als auch std :: lower_bound / equal_range etc ...

verwenden

Ich muss in der Lage sein, es zu sortieren und nach einem der ersten beiden Elemente der Struktur zu suchen. Also im Moment habe ich das:

%Vor%

Dadurch kann ich sowohl std :: sort als auch std :: lower_bound mit MSaTLess () aufrufen, um basierend auf dem aT-Element und mit MSbTLess () zu sortieren / zu suchen, basierend auf dem bT-Element.

Ich würde gerne von den Funktoren wegkommen und stattdessen C ++ 0x Lambdas verwenden. Für eine Sortierung, die relativ einfach ist, da das Lambda zwei Objekte vom Typ MS als Argumente akzeptiert.

Was ist jedoch mit den Lookup-Algorithmen für low_bound und andere binäre Suche? Sie müssen in der Lage sein, einen Komparator mit (MS, doppelten) Argumenten und auch umgekehrt, (Doppel, MS), richtig zu nennen? Wie kann ich diese am besten mit einem Lambda in einem Aufruf von lower_bound versorgen? Ich weiß, ich könnte ein MS-Dummy-Objekt mit dem erforderlichen Schlüsselwert erstellen, nach dem gesucht wird, und dann das gleiche Lambda verwenden wie mit std :: sort, aber gibt es eine Möglichkeit, dies zu tun, ohne Dummy-Objekte zu verwenden?

    
Paul Caheny 24.11.2010, 16:08
quelle

5 Antworten

15

Es ist etwas peinlich, aber wenn Sie die Definitionen von lower_bound und upper_bound vom Standard überprüfen, werden Sie sehen, dass die Definition von lower_bound den dereferenzierten Iterator als erste Parameter des Vergleichs (und der Wert Sekunde), während upper_bound den dereferenzierten Iterator Sekunde (und den Wert zuerst) setzt.

Also, ich habe das nicht getestet, aber ich denke, dass Sie wollen:

%Vor%

und

%Vor%

Das ist ziemlich scheußlich, und ohne ein paar weitere Dinge zu betrachten, bin ich nicht sicher, ob Sie wirklich davon ausgehen können, dass die Implementierung den Vergleicher nur so verwendet, wie er im Text beschrieben wird - das ist eine Definition des Ergebnisses , nicht die Mittel, um dorthin zu gelangen. Es hilft auch nicht mit binary_search oder equal_range .

Es ist nicht explizit in 25.3.3.1 angegeben, dass der Werttyp des Iterators in T konvertierbar sein muss, aber dies wird durch die Tatsache impliziert, dass die Anforderung für den Algorithmus T ist (in diesem Fall) , double ) muss LessThanComparable sein, nicht dass T mit dem Werttyp des Iterators in einer bestimmten Reihenfolge vergleichbar sein muss.

Ich denke also, es ist besser, nur einen Lambda (oder Funktor) zu verwenden, der zwei MS-Structs vergleicht und statt eines Double als Wert eine Dummy-MS mit dem korrekten Feld an den Wert übergibt, den Sie suchen für:

%Vor%

Wenn Sie MS keinen Konstruktor geben möchten (weil Sie wollen, dass es POD ist), dann können Sie eine Funktion schreiben, um Ihr MS-Objekt zu erstellen:

%Vor%

Wirklich, jetzt da es Lambdas gibt, wollen wir für diesen Job eine Version der binären Suche, die einen unären "Komparator" verwendet:

%Vor%

C ++ 0x bietet es jedoch nicht.

    
Steve Jessop 24.11.2010, 16:57
quelle
1

Die Algorithmen std :: sort, std :: lower_bound und std :: binary_search nehmen ein Prädikat, das zwei Elemente des Containers vergleicht. Jedes Lambda, das zwei MS-Objekte vergleicht und true zurückgibt, wenn sie in Ordnung sind, sollte für alle drei Algorithmen funktionieren.

    
Blastfurnace 24.11.2010 16:34
quelle
0

Nicht direkt relevant für das, was Sie über lambdas sagen, aber dies könnte eine Idee für die Verwendung der binären Suchfunktionen sein:

%Vor%

Wenn wir Find als Wert verwenden, müssen wir im Grunde keinen Komparator angeben, weil Find mit MS verglichen wird, indem das von uns angegebene Feld verwendet wird. Das ist die gleiche Sache wie die Antwort, die Sie hier gesehen haben: wie man sortiert STL-Vektor , wobei aber in diesem Fall der Wert und nicht der Komparator verwendet wird. Ich bin mir nicht sicher, ob es wirklich großartig wäre, es zu verwenden, aber es könnte sein, da es den zu suchenden Wert und das zu suchende Feld in einem einzigen kurzen Ausdruck angibt.

    
Steve Jessop 24.11.2010 19:00
quelle
0

Ich hatte das gleiche Problem für std::equal_range und habe eine alternative Lösung gefunden.

Ich habe eine Sammlung von Zeigern auf Objekte, die nach einem Typfeld sortiert sind. Ich muss den Bereich der Objekte für einen bestimmten Typ finden.

%Vor%

Obwohl es weniger effizient ist als ein dediziertes Prädikat, da es für jedes Objekt in meiner Sammlung einen unnötigen nullptr-Test einführt, bietet es eine interessante Alternative.

Abgesehen davon, wenn ich eine Klasse wie in Ihrem Beispiel verwende, tendiere ich dazu, folgendes zu tun. Ich kann nicht nur kürzer sein, sondern auch zusätzliche Typen mit nur einer Funktion pro Typ und nicht mehr als vier Operatoren pro Typ hinzufügen.

%Vor%     
Stephen Nutt 04.10.2012 21:18
quelle
0

In der ​​Definition von lower_bound und anderen STL-Algorithmen ist die Compare-Funktion so, dass der erste Typ dies tun muss passe die des Vorwärts-Iterators an und der zweite Typ muss mit dem von T (dh dem Wert) übereinstimmen.

%Vor%

So kann man tatsächlich Dinge von verschiedenen Objekten vergleichen (was die andere Antwort als Unary Comparator bezeichnet). In C ++ 11:

%Vor%

Und dies kann auch mit anderen STL-Algorithmusfunktionen verwendet werden.

    
wkr 04.09.2014 15:40
quelle

Tags und Links