STL Algo für jeden zweiten Iterator?
-
Ich gewöhne mir gerade mal an, die STL Methoden zu benutzen und nicht immer alles selber zu schreiben.
Ich hab ein double x und double y und einen vector<double> den ich loopen muss und abwechselnd mal x mal y addieren muss.
Nun hab ich mir std::transform mal angeguckt, sehe jedoch nicht, wie ich diese alterierende verhalten damit erzeugen kann.Gibt es da was schnelles, um dies zu bewerkstelligen?
-
Seikilos schrieb:
Ich hab ein double x und double y und einen vector<double> den ich loopen muss und abwechselnd mal x mal y addieren muss.
Meinst du sowas?
std::vector<double> vec = /* ... */; double x = vec[0] + vec[2] + vec[4] + /* ... */; double y = vec[1] + vec[3] + vec[5] + /* ... */;Falls ja, könntest du das folgendermassen machen. Den
operator()kannst du natürlich auch übersichtlicher implementieren...
struct xy_adder { xy_adder(double& x, double& y) : x(x), y(y), is_x(false) {} void operator() (double elem) { ((is_x ^= 1) ? x : y) += elem; } double& x; double& y; bool is_x; }; int main() { std::vector<double> v; // ... double x = 0; double y = 0; std::for_each(v.begin(), v.end(), xy_adder(x,y)); }Aber nicht immer ist ein separater Funktor die bessere Lösung. Manchmal reicht auch eine gewöhnliche Schleife.
Edit: Werner Salomon hat eigentlich Recht, beherzige seinen Vorschlag. Vielleicht hilft dir mein Code ja sonst mal...

-
.. klarer Fall von Designfehler. Du braucht eine Klasse Vektor(mathematisch) bzw. Position:
struct Pos { double m_x; double m_y; }; std::vector< Pos > ...;Ich bin sicher, dass das Dein Programm auch an anderen Stellen vereinfacht

Fertige Positions-Klassen dieser Art findest Du u.a. hier - musst halt immer den Z-Wert weglassen.
-
Willst du den vector<double> verändern oder die geänderten Werte in einen neuen vector packen? Falls ersteres müsste doch eigentlich for_each ausreichen.
Davon unabhängig kannst du dir ja einen Funktor schreiben, der double x und double y übergeben bekommt und der intern eine Zählvariable hochzählt bei jedem Aufruf von op(). Dann kannst du bei gerader Zählvariable x addieren und bei ungerader Zählvariable y addieren.
-
Öh, ja, nein, ja

Scherz. Also nochmal: Dieser Vektor ist linearisiert, wie ihr richtig erkannt habt. Das hat seinen Grund. Er wird so exakt als ein großer Speicherblock an die Grafikkarte geschickt.
Wir verwenden osg::Vec2d und da wir nicht sicher sein können, ob x und y dort als einzige Zustände des Structs existieren (oder mal n byte alignment oder so), können wir auch nicht ohne umkopieren riskieren, diese blind zu linearisieren.Der code ist mit ner for loop simpel:
for(unsigned i = 0; i < vertices.size()-1; i+=2) { vertices[i] = vertices[i]+_offset.x(); vertices[i+1] = vertices[i+1]+_offset.y(); }Ich dachte nur, es geht auch eleganter mit stl.
-
Also ich hatte jetzt gerade mal einen eigenen Iterator implementiert:
// transform algorithm example #include <iostream> #include <algorithm> #include <vector> using namespace std; int op_increase (int i) { return ++i; } template<class T> class double_iterator { private: typename vector<T>::iterator it; public: double_iterator(typename vector<T>::iterator i):it(i){} double_iterator operator++() { ++it; ++it; return it; } double_iterator operator++(int) { typename vector<T>::iterator temp(it); ++it; ++it; return temp; } bool operator!=(const double_iterator<T>& rhs) { return it!=rhs.it; } bool operator==(const double_iterator<T>& rhs) { return it==rhs.it; } T& operator*() { return *it; } }; int main () { vector<int> foo,bar; vector<int>::iterator it; // set some values: for (int i=1; i<7; i++) foo.push_back (i*10); // foo: 10 20 30 40 50 60 bar.resize(foo.size()); // allocate space transform (double_iterator<int>(foo.begin()),double_iterator<int>(foo.end()), double_iterator<int>(bar.begin()), op_increase); // bar: 11 0 31 0 51 0 cout << "bar contains:"; for (it=bar.begin(); it!=bar.end(); ++it) cout << " " << *it; cout << endl; return 0; }
-
Eleganter vielleicht, schneller nicht wirklich. Aber im Endeffekt furzegal. Die STL-Algorithmen zu verwenden, nur damit man sie verwendet hat, ist nicht besonders sinnvoll.
-
Seikilos schrieb:
Ich dachte nur, es geht auch eleganter mit stl.
Stichwort elegant
- na ja es gibt Möglichkeiten:#include <boost/iterator/iterator_adaptor.hpp> #include <algorithm> // transform #include <iostream> #include <vector> #include <iterator> // ostream_iterator #include <functional> // plus struct CycleIter : public boost::iterator_adaptor< CycleIter, std::vector< double >::const_iterator , boost::use_default, boost::forward_traversal_tag > { CycleIter( std::vector< double >::const_iterator first, std::vector< double >::const_iterator last ) : iterator_adaptor_( first ) , m_begin( first ) , m_end( last ) {} void increment() { if( ++base_reference() == m_end ) base_reference() = m_begin; } private: std::vector< double >::const_iterator m_begin; std::vector< double >::const_iterator m_end; }; int main() { using namespace std; vector< double > vertices( 8, 10.0 ); vector< double > offset(2); offset[0] = 1.0; // offset.x() offset[1] = 2.0; // offset.y() transform( vertices.begin(), vertices.end(), CycleIter( offset.begin(), offset.end() ), ostream_iterator< double >( cout << "Ergebnis: ", " "), plus< double >() ); // Bem.: statt ostream_iterator< double >(..) ginge natürlich auch vertices.begin() cout << endl; return 0; }Die Ausgabe ist:
Ergebnis: 11 12 11 12 11 12 11 12.. ob's brauchbar ist?