Nullen aus std::vector< std::vector< int > > löschen
-
ok, ich habe einen MasterVektor, der sich wieder aus Vektoren unterswchiedlicher länge zusammensetzt. Dazu kommt der Slavevektore, gleich lang, Nullen an den gleichen stellen. Jetzt sollen alle Nullen gelöscht werden. Ich hab das so implementiert:
[cpp] for(int k = 0; k < (int)MasterVector.size(); k++) { for(int n = 0; n < (int)MasterVector.at(k).size(); n++) { if (MasterVector.at(k).at(n) == 0) { MasterVector.at(k).erase(MasterVector.at(k).begin()+n); SlaveVector.at(k).erase(SlaveVector.at(k).begin()+n); } } } [/cpp]
Nur bleibt der Code hängen (Endlosschleife(???)).
Ne idee warum wär fett!
ANGs_Pino
-
wäre gut wenn du die vector deklarationen posten könntest...
naja, das erase löscht auch die elemente, irgendwann passierts dann dass n grösser wird als die grösse des vektors...
da man erase nur mit iteratoren anwenden kann würde ich direkt die vectoren per iterator durchgehen
for(vector<int>::iterator it = MasterVekor.begin(); it != MasterVektor.end(); ++it) { for(vector<int>::iterator jt = it->begin(); jt != it->end(); ++jt) { if ( *jt == 0 ) MasterVektor.erase(it); } }
ich kenne mich interatoren nicht so gut aus, aber ungefähr so sollte es klappen
-
Du musst dran denken, dass du den Iterator nur inkrementieren darfst, wenn du kein Element löschst. Zudem kann der Iterator ungültig werden.
for(std::vector<std::vector<int> >::iterator it = MasterVekor.begin(); it != MasterVektor.end(); ++it) { for(std::vector<int>::iterator jt = it->begin(); jt != it->end(); ) // keine Aktualisierung im Schleifenkopf { if ( *jt == 0 ) jt = MasterVektor.erase(it); // Zuweisung else ++jt; } }
-
for(int k = 0; k < (int)MasterVector.size(); k++) { for(int n = 0; n < (int)MasterVector.at(k).size();) { if (MasterVector.at(k).at(n) == 0) { MasterVector.at(k).erase(MasterVector.at(k).begin()+n); SlaveVector.at(k).erase(SlaveVector.at(k).begin()+n); } else n++; } }
@Nexus:
Ich würde das hier ebenfalls über die Operatoren machen und nicht über Iteratoren, weil er ja noch einen zweiten vector hat, wo er gleich mitlöschen kann,ohne sonst noch etwas berechnen zu müssen.
-
ANGs_Pino schrieb:
Nur bleibt der Code hängen (Endlosschleife(???)).
..sollte er nicht. Der Code ist zwar fehlerhaft - folgen zwei Nullen hintereinander so wird die zweite nicht gelöscht - aber er bleibt deshalb nicht hängen.
Wenn so eine Konstruktion - mit gleichzeitigem Löschen von Elementen in zwei Containern - notwendig wird, so liegt wahrscheinlich ein Designfehler vor.
Statt:vector< vector< int > > MasterVector; vector< vector< int > > SlaveVector;
ist wahrscheinlich die geeignetere Variante:
struct Irgendwas // ?? { int m_master; int m_slave; }; vector< vector< Irgendwas > > MastersAndSlaves;
dann lies sich dies mit einem std::remove(_if) und anschließendem std::erase einfacher und sicherer erledigen.
Für die Profis - sowas geht dann auch:
for_each( MasterVector.begin(), MasterVector.end(), bind( &vector< int >::erase, _1, bind( &remove< vector< int >::iterator, int >, bind( &vector< int >::begin, _1 ), bind( &vector< int >::end, _1 ), 0 ), bind( &vector< int >::end, _1 ) ) );
Gruß
Werner
-
drakon schrieb:
@Nexus:
Ich würde das hier ebenfalls über die Operatoren machen und nicht über Iteratoren, weil er ja noch einen zweiten vector hat, wo er gleich mitlöschen kann,ohne sonst noch etwas berechnen zu müssen.Du hast Recht, zumal man bei
std::vector
keinen Nachteil durch Random Access hat.Werner Salomon schrieb:
Für die Profis - sowas geht dann auch
Solche Konstrukte finde ich immer interessant. Ob diese die Sache vereinfachen, bleibt dahingestellt, aber Hauptsache, es sieht gut aus.
Vielleicht solltest du aber noch erwähnen, dass man dazu Boost benötigt (wobei die Profis das wissen sollten).
-
...oder gleich vector< vector< pair<int, int> > > MastersAndSlaves;
-
for_each( MasterVector.begin(), MasterVector.end(), bind( &vector< int >::erase, _1, bind( &remove< vector< int >::iterator, int >, bind( &vector< int >::begin, _1 ), bind( &vector< int >::end, _1 ), 0 ), bind( &vector< int >::end, _1 ) ) );
So proggen nur totale Vollhupen.
-
Werner Salomon schrieb:
Für die Profis - sowas geht dann auch:
for_each( MasterVector.begin(), MasterVector.end(), bind( &vector< int >::erase, _1, bind( &remove< vector< int >::iterator, int >, bind( &vector< int >::begin, _1 ), bind( &vector< int >::end, _1 ), 0 ), bind( &vector< int >::end, _1 ) ) );
Man kann sich das Leben auch unnötig schwer machen...
Ich würde das so schreiben:#include <vector> #include <algorithm> #include <boost/foreach.hpp> int main() { std::vector<std::vector<int> > masterVector; BOOST_FOREACH(std::vector<int>& v, masterVector) v.erase(std::remove(v.begin(), v.end(), 0), v.end()); }
Finde ich etwas ... leserlicher
-
hustbaer schrieb:
Werner Salomon schrieb:
Für die Profis - sowas geht dann auch:
for_each( MasterVector.begin(), MasterVector.end(), bind( &vector< int >::erase, _1, bind( &remove< vector< int >::iterator, int >, bind( &vector< int >::begin, _1 ), bind( &vector< int >::end, _1 ), 0 ), bind( &vector< int >::end, _1 ) ) );
Man kann sich das Leben auch unnötig schwer machen...
Ich würde das so schreiben:#include <vector> #include <algorithm> #include <boost/foreach.hpp> int main() { std::vector<std::vector<int> > masterVector; BOOST_FOREACH(std::vector<int>& v, masterVector) v.erase(std::remove(v.begin(), v.end(), 0), v.end()); }
Finde ich etwas ... leserlicher
Hab ich was verpasst? Wo ist der SlaveVector hin?
-
JezMalButterBeiDieFische schrieb:
SlaveVector hin?
der heißt jetzt v.
-
Vorher wurde doch aus zwei Vektoren gelöscht und jetzt doch nur aus einem, oder?
-
JezMalButterBeiDieFische schrieb:
Vorher wurde doch aus zwei Vektoren gelöscht und jetzt doch nur aus einem, oder?
aus jedem v alle nullen.
std::vector<std::vector<int> > masterVector; BOOST_FOREACH(std::vector<int>& v, masterVector) v.erase(std::remove(v.begin(), v.end(), 0), v.end());
ist
std::vector<std::vector<int> > masterVector; for(auto i=masterVector.begin();i!=masterVector.end();++i)) std::vector<int>& v=*i; v.erase(std::remove(v.begin(), v.end(), 0), v.end());
std::remove(v.begin(), v.end(), 0) schmeißt sozusagen alle nullen raus, naja, löschen kann die funktion nicht. was sie aber kann, ist die nullen ans ende schieben und die richtigen werte an den anfang. und sie gibt zurück, wo nach dem umverschieben die nullen anfangen.
v.erase(woDieNullenANfangen); löscht dann die ganzen nullen.
-
aber das ist doch immer nur ein vector pro for-schleife, vorher waren es zwei in einer schleife.
-
JezMalButterBeiDieFische schrieb:
aber das ist doch immer nur ein vector pro for-schleife, vorher waren es zwei in einer schleife.
in remove steckt innendrin eine schleife.
-
Ne er hat schon Recht - vorher gab's zwei Schleifen UND zwei std::vector.
Der "slave Vector" is weg, weil ... den irgendwer mal weggelassen hat.
Mein Code bezog sich bloss auf das "bind-Monster" von Werner -- dass man das halt wesentlich einfacher (und kürzer) schreiben kann.BTW: in C++0x wird's ja gottseidank lambda-expressions geben, dann muss man kaum mehr "binden".
-
Wie würde das denn mit Lambda-Ausdrücken aussehen? Wäre es dann tatsächlich einfacher bzw. übersichtlicher?
-
ca. gleich wie die BOOST_FOREACH variante, nur ohne den "Hack" üder das Marko eben:
for_each(MasterVector.begin(), MasterVector.end(), [](std::vector<int>& v) { v.erase(std::remove(v.begin(), v.end(), 0), v.end()); });