Vector: min_element eines Vector mit Objekten
-
Klotz schrieb:
Hi,
bevor ich damit starte, Eure Weisungen durchzugehen, habe ich ein Problem. Der compiler meldet mir ständig, dass die Variable DKNummer kein Bestandteil des Vector ist.
DKNummer ist ein Bestandteil von AN und in deinem Vector speicherst du Objekte vom Typ AN.
Und bevor das Nächste was du probierst auch nicht funktioniert: AN ist auch kein Bestandteil des Vectors. Lies dir einfach mal durch, wie du auf die im Vector gespeicherten Daten zugreifen kannst.
Edit: z.B. hier: http://www.cplusplus.com/reference/vector/vector/ unter Element access
-
Klotz schrieb:
Der compiler meldet mir ständig, dass die Variable DKNummer kein Bestandteil des Vector ist.
Du scheinst dir das so vorzustellen, dass der vector<AN> einen "Untervektor" vector<int> DKNummer enthält, der wiederum die DKNummer-Member deiner ANs enthält.
Das ist aber nicht der Fall.
-
Hallo,
habe jetzt endlich Zeit, weiter zu machen. Leider weiß ich nicht, wie ich die Iteratorfunktion schreiben soll.
for ( vector<AN>::iterator it = Auftragnehmerkopie.begin(); it !=Auftragnehmerkopie.end();) { DKmin=*min_element(it->DKNummer.begin(),it->DKNummer.end()); /* if { } */ else { ++it; } }
Dachte, dass es so jetzt stimmen müsste, aber der compiler meldet:
"error: request for member 'begin' in 'it.gnu_cxx:_normal_iterator<...which is of non-class type int"Das sagt mir nicht viel. Ist jetzt DKmin falsch (int), oder der it->... code- Teil?
-
Ach Mist, ich komme nicht weiter
-
Hallo,
DKNummer ist ein 'int' und hat keine begin oder end-Funktion!
Nur ein vector stellt diese bereit.Wie ich schon schrieb, benötigst du die Funktion mit der Vergleichsfunktion als Parameter:
min_element(Auftragnehmerkopie.begin(), Auftragnehmerkopie.end(), cmp_by_DKNummer);
Und nun noch die Vergleichsfunktion 'cmp_by_DKNummer' entsprechend implementieren...
-
In der Doku findest du ein Beispiel:
-
Hallo,
Mensch. Danke schon mal. Ich glaube, ich habe es jetzt. Ich schreibe mal die Funktion fertig und poste dann das Ergebnis. Ich stand echt auf dem Schlauch. Vielen Dank.
Mir war nicht klar, dass min_element drei Parameter braucht.
Grüße,
Chris
-
Es gibt auch die Variante mit nur zwei Parametern, aber dann vergleicht diese Funktion anhand des Operator < (der aber für deine Klasse AN bisher wohl nicht definiert ist) - aber das steht auch alles in den geposteten Links zur Doku.
-
Hallo,
ich poste mal einen Zwischenstand und würde mich über Rückmeldung freuen, weil ich eine Fehlermeldung bekomme, die ich noch nicht zuordnen kann.
In WinMain:
if (!Auftragnehmerkopie.empty()) { for ( vector<AN>::iterator it = Auftragnehmerkopie.begin(); it !=Auftragnehmerkopie.end();) { if (it != Auftragnehmerkopie.end()&&ANGroesse>1) { DKpos=std::min_element(it->DKNummer, it->DKNummer+ANGroesse,PruefeVektorausgabe); //* DKmin=Auftragnehmerkopie[DKpos].DKNummer;
bool PruefeVektorausgabe(const AN& x, const AN& y) { return x.DKNummer<y.DKNummer; }
Der compiler meldet mir für die Zeile // *
"invalid type argument of unary '*' (have 'int')Ich ahne, dass das was mit dem dritten Parameter von min_element zu tun hat.
Generell habe ich versucht, über zwei Instanzen von <AN> die DKNummer zu vergleichen. Das scheint aber nicht zu funktionieren. Vielleicht, weil da ein Zeiger in die Funktion mitgegeben wird und kein (int)? Und die Funktion ist eine (bool)? Ist das so überhaupt richtig? Müsste nicht eine (int) erfolgen?
Kann mir das jemand erklären? Das wäre sehr nett.
-
Th69 schrieb:
min_element(Auftragnehmerkopie.begin(), Auftragnehmerkopie.end(), cmp_by_DKNummer);
Th69 hat doch schon geschrieben, wie dein Code aussehen müsste. Hast du dir die Doku zu min_element durchgelesen? Wo steht da, dass man das mit "int" aufrufen kann? it->DKNummer ist ein int
Die ganze Schleife kannst du dir schenken, das erledigt min_element für dich, wenn du die passenden iteratoren übergibst.
-
Wie bereits gesagt: min_element nimmt Iteratoren und liefert auch einen zurück.
Iteratoren gehören zum grundlegenden Konzept der STL. Schau dir das noch einmal genauer an.
-
Hallo.
Ich bin jetzt zumindest in der Lage, EIN Mindestelement zu filtern und dessen Position und Wert zu speichern.
if (!Auftragnehmerkopie.empty()) { std::vector<AN>::iterator resultDK=std::min_element(Auftragnehmerkopie.begin(), Auftragnehmerkopie.end(), PruefeVektorausgabe); DKpos=std::distance(Auftragnehmerkopie.begin(),resultDK); DKmin=Auftragnehmerkopie[DKpos].DKNummer; //... bool PruefeVektorausgabe(const AN& x, const AN& y) { return x.DKNummer<y.DKNummer; } }
Nun ergibt sich für mich folgende Frage. Da es mehrere Vector Elemente gibt, die den selben DKNummer Wert haben, möchte ich unter diesen noch drei weitere Werte filtern, um das ELement zu erhalten, das überall den niedrigsten Wert hat, dieses ausgeben und dann aus dem Vector löschen.
Ich möchte in diesem Zusammenhang wissen, ob ich DKmin als Parameter in der std::min_element Abfrage als Parameter mitgeben kann, so dass das nächste Mindestelement nur unter den Elementen gesucht wird, die DKNummer==DKmin erfüllen; in etwa:
resultKAB=std::min_element(Auftragnehmerkopie.begin()&&DKNummer==DKmin, Auftragnehmerkopie.end(), PruefeKABausgabe);
Wie kann ich so etwas schaffen? Leider geben da meine Bücher keine Antwort und google hilft mir auch nicht viel weiter. Geht das überhaupt?
-
Es gibt kaum Sachen, die nicht gehen...
bool PruefeVektorausgabe(const AN& x, const AN& y){ if(x.DKNummer == y.DKNummer){ ... } return x.DKNummer<y.DKNummer; }
-
Folgende beiden Wege finde ich für den Vergleich anhand mehrerer Bedingungen am einfachsten:
Variante 1, make_tuple:
bool PruefeVektorausgabe(const AN& x, const AN& y){ return make_tuple(x.DKNummer, x.andere_variable, x.noch_was_anderes) < make_tuple(y.DKNummer, y.andere_variable, y.noch_was_anderes); }
Tuples sortieren sich von links nach rechts, d.h. das vergleicht also erst
DKNummer
, dann bei Gleichheitandere_variable
, und wenn dann immer noch beides gleich ist, wirdnoch_was_anderes
verglichen.Variante 2:
bool PruefeVektorausgabe(const AN& x, const AN& y){ if (x.DKNummer < y.DKNummer) return true; if (x.DKNummer != y.DKNummer) return false; if (x.andere_variable < y.andere_variable) return true; if (x.andere_variable != y.andere_variable) return false; return x.noch_was_anderes < y.noch_was_anderes; }
Die Variante 2 finde ich deutlich besser als Schlangenmenschs Weg mit if und dann einem Block bei Gleichheit. Der führt nämlich zu Verschachtelungen und ist schwerer zu lesen, insbesondere wenn man viele Vergleichsvariablen hat.
-
@wob: tatsächlich finde ich deine Ansätze auch besser als meinen. Meiner war vor allem als kurzer Denkanstoß an den TE gedacht, dass man in der Sortierfunktion mehr machen kann als nur einen Vergleich.
-
Hi,
Danke für die Denkanstösse. So langsam verstehe ich den Umgang mit Vektoren.
Vielleicht lassen sich alle Zugriffe in der bool Funktion unterbringen, die von std::min_element aufgerufen wird. AM Ende sollte quasi das Vektorobjektelement stehen, dass in allen vier Abfragen den niedrigsten Wert hat.
Darf ich das so verstehen, dass über die compare Funktion von min oder max quasi eine Zugriffsfunktion auf die Vektorelemente erzeugt wird?
Irgendwie, ohne mich gut auszukennen, erscheint mir das nicht als der Weisheit letzter Schluss.
Idealer fände ich einen Iteratordurchlauf, bei dem ich über Parameter der ersten beiden Indexfunktionen meine Filter zuschalten kann... vielleicht gibt es das auch? Zunächst kann ich aber mal weiter testen.
Als Neuling in c++ stürzt da doch eine Menge auf einen ein, was man nach und nach abarbeiten muss. Wenn das nicht so viel Spaß machen würde, hätte ich wohl längst mit Briefmarken angefangen
Ich mache mich mal dran. Nochmals Danke, Leute.
-
Klotz schrieb:
Darf ich das so verstehen, dass über die compare Funktion von min oder max quasi eine Zugriffsfunktion auf die Vektorelemente erzeugt wird?
Nein
Klotz schrieb:
Idealer fände ich einen Iteratordurchlauf, bei dem ich über Parameter der ersten beiden Indexfunktionen meine Filter zuschalten kann...
Hä?
Wenn du die von wob vorgeschlagene Funktion benutzt, bekommst du einen Iteratror, der auf dein gewünschtes Element zeigt.
Klotz schrieb:
std::vector<AN>::iterator resultDK=std::min_element(Auftragnehmerkopie.begin(), Auftragnehmerkopie.end(), PruefeVektorausgabe); DKpos=std::distance(Auftragnehmerkopie.begin(),resultDK); DKmin=Auftragnehmerkopie[DKpos].DKNummer;
Warum nicht
std::vector<AN>::iterator resultDK=std::min_element(Auftragnehmerkopie.begin(), Auftragnehmerkopie.end(), PruefeVektorausgabe); DKmin=resultDK->DKNummer;
-
Klotz schrieb:
Vielleicht lassen sich alle Zugriffe in der bool Funktion unterbringen, die von std::min_element aufgerufen wird. AM Ende sollte quasi das Vektorobjektelement stehen, dass in allen vier Abfragen den niedrigsten Wert hat.
Verstehe ich nicht. Was ist, wenn du Elemente (x=1,y=2) und (x=2,y=1) hast? Dann gibt es kein Element, das in allen Abfragen den niedrigsten Wert hat (das erste hat bei x den niedrigsten, das zweite bei y). Was dir hier gezeigt wurde, war eine Sortierung derart, dass alle Elemente zunächst unabhängig von y nach x sortiert werden. Nur bei Gleichheit in der ersten Variablen wird die zweite herangezogen.
Darf ich das so verstehen, dass über die compare Funktion von min oder max quasi eine Zugriffsfunktion auf die Vektorelemente erzeugt wird?
Nein, die compare-Funktion erzeugt keine andere Funktion! Sie ist eine Funktion, die genau 2 Elemente des Vektors vergleicht und als Returnwert angibt, ob das erste kleiner als das zweite ist (nach einer von dir zu implementierenden Definition von "kleiner"). Diese Funktion wird dann von min_element aufgerufen.
Idealer fände ich einen Iteratordurchlauf, bei dem ich über Parameter der ersten beiden Indexfunktionen meine Filter zuschalten kann... vielleicht gibt es das auch? Zunächst kann ich aber mal weiter testen.
Sorry, verstehe ich nicht.
Welche Filter? Was meinst du mit "Indexfunktionen"?
Wenn du filtern willst, dann such mal nach erase-remove-Idiom. Alternativ könnte man natürlich in der Vergleichsfunktion alle unerwünschten Elemente als "sehr groß" markieren, sodass min_element ein anderes wählen würde (dann muss man noch den Spezialfall "alle unerwünscht" behandeln).
Ansonsten kannst du einen Iteratordurchlauf auch manuell machen:
for (auto it = Auftragnehmerkopie.begin(); it != Auftragnehmerkopie.end(); ++it) { ... }
Allerdings frage ich mich gerade, was eigentlich genau dein Ziel ist.