Verwendung eines (mathematischen) Vektors in einer std :: map

8

Related: Was kann ich als std::map keys verwenden?

Ich musste ein Mapping erstellen, bei dem bestimmte Schlüsselpositionen im Raum Listen von Objekten zugeordnet werden. std::map schien der richtige Weg dafür zu sein.

Also gebe ich ein std::map auf einem xyz Vector

ein %Vor%

, und ich mache eine std::map<Vector, std::vector<Object*> > . Also notiere den Schlüssel hier ist nicht a std::vector , es ist ein Objekt von class Vector , das ist nur ein mathematischer xyz Vektor, den ich selbst mache.

Um eine "strikt schwache Reihenfolge" zu erzeugen, habe ich die folgende Überladung für operator< :

geschrieben %Vor%

Es ist ein bisschen lang, aber es macht grundsätzlich so, dass jeder Vektor konsistent als kleiner als jeder andere Vektor ((-1, -1, -1) & lt; (-1, -1,1) und ( -1, -1, 1) & gt; (-1, -1, -1) zum Beispiel).

Mein Problem ist, dass es wirklich künstlich ist und obwohl ich es programmiert habe und es funktioniert, finde ich heraus, dass es meine Vector-Klasse (mathematisch) mit dieser wirklich seltsamen, künstlichen, nicht auf Mathematik basierenden Vorstellung "verschmutzt". weniger als "für einen Vektor.

Aber ich muss ein Mapping erstellen, wo bestimmte Schlüsselpositionen im Raum auf bestimmte Objekte abgebildet werden, und std :: map scheint der Weg dafür zu sein.

Vorschläge? Out-of-Box-Lösungen sind willkommen!

    
bobobobo 18.08.2010, 18:27
quelle

5 Antworten

5

Anstatt operator< für Ihre Schlüsselklasse zu definieren, können Sie der Karte einen benutzerdefinierten Vergleicher zuweisen. Dies ist ein Funktionsobjekt, das zwei Argumente akzeptiert und true zurückgibt, wenn das erste vor dem zweiten steht. Etwas wie das:

%Vor%     
Mike Seymour 18.08.2010, 18:35
quelle
3

Sie können es von der Klasse trennen. Dann spezifizieren Sie es als Vergleichsoperator für die std :: map.

%Vor%

Where Compare ist eine Funktion (oder ein Funktor), die Vektorobjekte miteinander vergleichen kann.
Ich denke auch, dass Sie Ihre Vergleichsoperation vereinfachen können.

%Vor%

Beachten Sie, dass wir weniger als größer testen und dann gleich durchfallen. Persönlich mag ich die Einfachheit dieses Stils. Aber ich sehe oft, dass das so komprimiert ist:

%Vor%     
Martin York 18.08.2010 18:53
quelle
1

Ich denke std::tr1::unordered_map ist genau das, was Sie brauchen. Es ist keine strenge schwache Reihenfolge erforderlich. GCC hat etwas ähnliches in tr1 namespace. Oder gehen Sie zu Boost.Unordered .

Die ungeordneten Gegenstücke des mehr Fußgänger map oder set gibt Ihnen zwei Vorteile:

  • Sie müssen keinen less-than-Operator definieren, wenn keiner Sinn ergibt

  • Hashtabellen können bessere Ergebnisse erzielen als ausgeglichene Binärbäume, wobei letzterer die bevorzugte Methode zur Implementierung der bestellten map - oder set -Strukturen ist. Dies hängt jedoch von Ihren Datenzugriffsmustern / Anforderungen ab.

Also, mach einfach weiter und benutze:

%Vor%

Dies verwendet eine Standard-Hash-Funktion, die sich um das Einfügen / Suchen Ihrer Map kümmert.

PS: Das > > dingy wird in den kommenden Standard und damit zukünftigen Compiler-Versionen behoben werden.

    
dirkgently 18.08.2010 18:36
quelle
1

Es ist normal, dass Sie feststellen, dass Ihre Klasse dadurch verunreinigt ist. Es ist auch aus Sicht der CS verschmutzt.

Der normale Weg, einen solchen Operator zu definieren, ist durch (möglicherweise Freund) freie Funktionen.

Die erste Frage, die Sie sich stellen sollten, ist: macht es Sinn? Das Problem ist, dass Sie eine Methode für Ihre Klasse definiert haben, die nur in einem begrenzten Kontext sinnvoll ist, aber überall zugänglich ist. Deshalb tritt das "Verschmutzungsgefühl" auf.

Wenn ich nun ein solches Mapping von einem Vector zu einer Sammlung von Object s benötigen würde, sind hier die Fragen, die ich mir stellen möchte:

  • Muss ich Vector bestellen? Ja: std::map , Nein: std::unordered_map oder std::tr1::unodered_map oder std::hash_map oder boost::unordered_map .
  • Besitzt diese Sammlung Object ? Ja: boost::ptr_vector<Object> oder std::vector< std::unique_ptr<Object> > , Nein: std::vector<Object*>

Nun, in beiden Fällen ( map und unordered_map ) brauche ich etwas, um meinen Schlüssel zu transformieren. Die Sammlung bietet ein zusätzliches Template-Argument, das einen Funktor-Typ annimmt.

Vorsicht: Wie in einer anderen Antwort erwähnt, ist die Gleitkommadarstellung in einem Computer schwierig, daher müssen Sie wahrscheinlich die Bedeutung von Gleichheit lockern und die Zahlen niedrigerer Ordnung ignorieren (wie viele davon von Ihren Berechnungen abhängen).

    
Matthieu M. 19.08.2010 06:42
quelle
0

Ich denke, Ihre Vorgehensweise ist in Ordnung. Wenn Sie sich Sorgen machen, die Vector-Klasse zu verschmutzen, dann glaube ich, dass eine eigenständige Funktion genauso gut funktioniert:

%Vor%

Aber nur ein Wort der Warnung: Was Sie hier tun, ist ziemlich riskant. Bei Gleitkommaberechnungen treten häufig Fehler auf. Angenommen, Sie fügen einen Punkt in Ihre Karte ein. Dann berechnen Sie einen Punkt und überprüfen Sie die Karte, um zu sehen, ob es da ist. Auch wenn der zweite Punkt aus streng mathematischer Sicht derselbe ist wie der erste, gibt es keine Garantie, dass Sie ihn in der Karte finden.

    
Peter Ruderman 18.08.2010 18:32
quelle