I'm not very familiar with iterators in C++. Basically I have a container, which was written by someone else, which I do populate with records (I create many containers). However, I need to output tuples, instead each container separately as e.g.:
a1 | a2 | ... | an
given that each a's belong to separate containers. I will take as an e.g., a vector container:
vector<int> v;
vector<int>::iterator iter;
v.push_back(1);
v.push_back(2);
v.push_back(3);
for (iter = v.begin(); iter != v.end(); iter++)
cout << (*iter) << endl;
The code above will output records only from one containers, but I need to combine output from many containers (all the same length), how would I go on constructing tuples from all of them?
thanx in advance!
If your project is using Boost already, you could use zip_iterator.
You can also try to implement a simpler version of it (the full implementation is quite complicated).
You can use indices, if container supports random-access, for example
for (size_t i = 0; i < v.size(); ++i)
{
cout << v[i] << " " << v1[i] << endl;
}
You can use many iterators
vector<int>::iterator iter1;
for (iter = v.begin(), iter1 = v1.begin(); iter != v.end(); ++iter, ++iter1)
{
cout << *iter << " " << *iter1 << endl;
}
Further to pmr's answer and your comment thereon seeking a pointer towards implementation, the basic idea for a "zipping" iterator is easy to realise:
#include <iostream>
#include <vector>
template <typename T, typename U>
struct Zip
{
Zip(const T& t, const U& u, char sep = '|')
: it_(t.begin()), iu_(u.begin()), te_(t.end()), ue_(u.end()), sep_(sep)
{ }
Zip& operator*() const { return *this; }
Zip& operator++() { ++it_; ++iu_; return *this; }
operator bool() const { return it_ != te_ && iu_ != ue_; }
friend std::ostream& operator<<(std::ostream& os, const Zip& z)
{
return os << *z.it_ << z.sep_ << *z.iu_;
}
private:
typename T::const_iterator it_, te_;
typename U::const_iterator iu_, ue_;
char sep_;
};
int main()
{
std::vector<int> v1;
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
std::vector<std::string> v2;
v2.push_back("one");
v2.push_back("two");
v2.push_back("three");
v2.push_back("four");
for (Zip<std::vector<int>, std::vector<std::string> > zip(v1, v2); zip; ++zip)
std::cout << zip << '\n';
}
You could create a Zip iterator with one/both sides being a Zip iterator to handle more (than 2) iterators, or generalise the above using variadic templates.
vector<int> v;
set<float> v2;
vector<int>::iterator iter;
set<float>::iterator iter2;
for (iter = v.begin(), iter2 = v2.begin();
iter != v.end() && iter2 != v2.end();
++iter, ++iter2)
cout << (*iter) << (*iter2) << endl;
Keep in mind that this loop iterates at most as much as the length of the smallest container.
Related
so far I wrote this:
template <typename TType>
void print_vector(const std::vector<TType>& vec)
{
typename std::vector<TType>::const_iterator it;
std::cout << "(";
for(it = vec.begin(); it != vec.end(); it++)
{
if(it!= vec.begin()) std::cout << ",";
std::cout << (*it);
}
std::cout << ")";
}
template<>
template <typename T2>
void print_vector(const std::vector< std::vector<T2> >& vec)
{
for( auto it= vec.begin(); it!= vec.end(); it++)
{
print_vector(*it);
}
}
The first function works fine for things like std::vector< double> and so on. Now I want to be able to print std::vector< std::vector< TType>> things as well. The second part doesn't compile, but that's the "idea" I have of solving my task. Any suggestions on how to achieve that kind of behavior?
Compilation Error: too many template-parameter-lists
Remove the template<> part, function template overloading would work fine.
template <typename TType>
void print_vector(const std::vector<TType>& vec)
{
typename std::vector<TType>::const_iterator it;
std::cout << "(";
for(it = vec.begin(); it != vec.end(); it++)
{
if(it!= vec.begin()) std::cout << ",";
std::cout << (*it);
}
std::cout << ")";
}
template <typename T2>
void print_vector(const std::vector< std::vector<T2> >& vec)
{
for( auto it= vec.begin(); it!= vec.end(); it++)
{
print_vector(*it);
}
}
You may actually want to go for a more generic solution to the problem, allowing to print pretty much any iterable type:
#include <vector>
#include <iostream>
template <typename Iterable>
std::ostream& operator<<(std::ostream& os, const Iterable& vals)
{
for (const auto& val : vals)
os << val << std::endl;
return os;
}
int main()
{
auto simple_vec = std::vector<int>{3, 5 , 7};
std::cout << simple_vec;
auto nested_vec = std::vector<std::vector<int>>{{1, 2}, {3, 4}};
std::cout << nested_vec;
}
For further improvements on this solution, you could try using SFINAE, to make sure the templated << is only available for iterable types.
If you make your function to print base types and override for vector using itself recursively:
template<typename T>
void print( const T &t )
{
std::cout << t;
}
template<typename T>
void print( const std::vector<T> &v )
{
std::cout << '[';
for( auto it = v.begin(); it != v.end(); ++it ) {
if( it != v.begin() ) std::cout << ',';
print( *it );
}
std::cout << ']';
}
then you do not need to write special one for vector of vectors or vector of vectors of vectors and so on.
live example
I have a vector of Student which has a field name.
I want to iterate over the vector.
void print(const vector<Student>& students)
{
vector<Student>::iterator it;
for(it = students.begin(); it < students.end(); it++)
{
cout << it->name << endl;
}
}
This is apparently illegal in C++.
Please help.
You have two (three in C++11) options: const_iterators and indexes (+ "range-for" in C++11)
void func(const std::vector<type>& vec) {
std::vector<type>::const_iterator iter;
for (iter = vec.begin(); iter != vec.end(); ++iter)
// do something with *iter
/* or
for (size_t index = 0; index != vec.size(); ++index)
// do something with vec[index]
// as of C++11
for (const auto& item: vec)
// do something with item
*/
}
You should prefer using != instead of < with iterators - the latter does not work with all iterators, the former will. With the former you can even make the code more generic (so that you could even change the container type without touching the loop)
template<typename Container>
void func(const Container& container) {
typename Container::const_iterator iter;
for (iter = container.begin(); iter != container.end(); ++iter)
// work with *iter
}
Use const_iterator instead. An iterator allows modification of the vector, so you can't get one from a const container.
Also, the idiomatic way to write this loop uses it != students.end() instead of < (though this should work on a vector).
C++11 style:
void print(const vector<Student>& students) {
for(auto const& student : students) {
cout << student.name << endl;
}
}
Instead of vector<Student>::iterator, use vector<Student>::const_iterator.
void print(const vector<Student>& students)
{
vector<Student>::const_iterator it; // const_iterator
for(it = students.begin(); it != students.end(); it++)
{
cout << it->name << endl;
}
}
void print(const vector<Student>& students)
{
for(auto it = students.begin(); it != students.end(); ++it)
{
cout << it->name << endl;
}
}
I would like to know if I can have a generic iterator to access the elements in the the vectors. I have for different vectors but only one function to display the elements.
If I can have a generic iterator than my method can work out smoothly. Please advice if it is possible.
Point2,Point3,Line2,Line3 are 4 different classes. The method takes in a vector object which I have created in another method.
template <typename VecObject>
void Display(VecObject v) {
if (filterCriteria == "Point2") {
vector<Point2>::iterator it;
} else if (filterCriteria == "Point3") {
} else if (filterCriteria == "Line2") {
} else if (filterCriteria == "Line3") {
}
for ( it = v.begin(); it!=v.end(); ++it) {
cout << *it << endl;
}
}
This what i used to do ealier and it work find. I now need to to implement using iterators
//for (int i = 0; i < v.size(); i++) {
// cout << v[i];
// }
You have access to a vector's iterator types via iterator and const_iterator, so you need no switching:
template <typename VecObject>
void Display(const VecObject& v) {
typename VecObject::const_iterator it;
for ( it = v.begin(); it!=v.end(); ++it) {
cout << *it << endl;
}
}
Note that I changed the signature to take a const reference as opposed to a value. With the original signature, you would be needlessly copying the vector each time you call the function.
Alternatively, you can implement the function to take two iterators:
template <typename Iterator>
void Display(Iterator first, Iterator last) {
for (Iterator it = first; it!=last; ++it) {
cout << *it << endl;
}
}
and call it like this:
Display(v.begin(), v.end());
template<typename VectorObject>
void Display(VecObject v) {
typename VectorObject::const_iterator it = v.begin();
for (; it!=v.end(); ++it) {
cout << *it << endl;
}
}
Assume that your VectorObject implements iterators you can access to it's iterator type directly.
Usage:
int main()
{
std::vector<int> intv(2, 5);
std::vector<float> fv(2, 10);
Display(intv);
Display(fv);
return 0;
}
I have a vector of Student which has a field name.
I want to iterate over the vector.
void print(const vector<Student>& students)
{
vector<Student>::iterator it;
for(it = students.begin(); it < students.end(); it++)
{
cout << it->name << endl;
}
}
This is apparently illegal in C++.
Please help.
You have two (three in C++11) options: const_iterators and indexes (+ "range-for" in C++11)
void func(const std::vector<type>& vec) {
std::vector<type>::const_iterator iter;
for (iter = vec.begin(); iter != vec.end(); ++iter)
// do something with *iter
/* or
for (size_t index = 0; index != vec.size(); ++index)
// do something with vec[index]
// as of C++11
for (const auto& item: vec)
// do something with item
*/
}
You should prefer using != instead of < with iterators - the latter does not work with all iterators, the former will. With the former you can even make the code more generic (so that you could even change the container type without touching the loop)
template<typename Container>
void func(const Container& container) {
typename Container::const_iterator iter;
for (iter = container.begin(); iter != container.end(); ++iter)
// work with *iter
}
Use const_iterator instead. An iterator allows modification of the vector, so you can't get one from a const container.
Also, the idiomatic way to write this loop uses it != students.end() instead of < (though this should work on a vector).
C++11 style:
void print(const vector<Student>& students) {
for(auto const& student : students) {
cout << student.name << endl;
}
}
Instead of vector<Student>::iterator, use vector<Student>::const_iterator.
void print(const vector<Student>& students)
{
vector<Student>::const_iterator it; // const_iterator
for(it = students.begin(); it != students.end(); it++)
{
cout << it->name << endl;
}
}
void print(const vector<Student>& students)
{
for(auto it = students.begin(); it != students.end(); ++it)
{
cout << it->name << endl;
}
}
I've made a method to scroll/wrap around a map of items, so that if the end is reached, the method returns the first item and vice-versa.
Is there more succinct way of doing this?
MyMap::const_iterator it = myMap.find(myKey);
if (it == myMap.end())
return 0;
if (forward) {
it++;
if (it == myMap.end()) {
it = myMap.begin();
}
} else {
if (it == myMap.begin()) {
it = myMap.end();
}
it--;
}
You could implement the wrap-around behavior directly into a new iterator-class - templated to be a wrapper for some actual iterator, that supplies a more elegant interface to the caller (so that its increment and decrement operators do the wrap-around automatically).
Also - be careful of the empty container. You don't want to "wrap-around" when there are no elements in the container.
You can do this with a template. As was stated by a previous poster, this can be cumbersome from the standpoint that it never reaches the end so the user must somehow control this. I'm assuming you have a good reason, perhaps producing some round robin behavior.
#include <iostream>
#include <string>
#include <vector>
#include <set>
#include <map>
using namespace std;
template <class T>
class ScrollIterator
{
public:
ScrollIterator(T &myCtr, typename T::iterator pos)
:ctr(myCtr),
it(pos)
{
}
ScrollIterator operator++()
{
if (++it == ctr.end()) { it = ctr.begin(); }
return *this;
}
bool operator!=(const ScrollIterator &rhs) const
{
return (this->it != rhs.it);
}
bool operator!=(const typename T::const_iterator &rhsIT) const
{
return (this->it != rhsIT);
}
typename T::value_type operator*() const
{
return *it;
}
private:
T &ctr;
typename T::iterator it;
};
int main (int argc, char *argv[])
{
vector<int> v;
v.push_back(2);
v.push_back(3);
v.push_back(5);
v.push_back(7);
int i = 0;
for (ScrollIterator<vector<int> > it(v,v.begin()); it != v.end() && i < 10; ++i, ++it)
{
cout << "Vector = " << i << " Value: " << *it << "\n";
}
set<string> s;
s.insert("c");
s.insert("a");
s.insert("b");
i = 0;
for (ScrollIterator<set<string> > it(s,s.begin()); it != s.end() && i < 10; ++i, ++it)
{
cout << "Set = " << i << " Value: " << *it << "\n";
}
map<string, int> y;
y["z"] = 10;
y["y"] = 20;
y["x"] = 30;
i = 0;
for (ScrollIterator<map<string, int> > it(y,y.begin()); it != y.end() && i < 10; ++i, ++it)
{
cout << "Map = " << i << " Iterator: " << (*it).first << " = " << (*it).second << "\n";
}
return 1;
}
You can use upper_bound and lower_bound. For example:
if (myMap.empty()) return 0;
MyMap::const_iterator it;
if (forward) {
it = myMap.upper_bound(myKey);
if (it == myMap.end()) it = myMap.begin();
} else {
it = myMap.lower_bound(myKey);
if (it == myMap.begin()) it = myMap.end();
--it;
}
This will also behave differently if "myKey" doesn't exist in the map. It will take up from where the key would have been rather than going to the end or the beginning.
You could implement a cyclical iterator.
This is a difficult design. If reaching the "end" wraps around to the "beginning", how do you represent an empty container? The wraparound idea models an infinite sequence or a ring, but without a means to detect whether the iterator is still pointing to a valid position.
This problem is reminiscent of attempts to write a variable-sized ring buffer (such as a queue) without using a "dummy entry": How does one distinguish an empty ring from a full ring? Storing a base position and a size is only appropriate for random-access storage (as opposed to linked nodes), and is less amenable to locking optimization than pointer or index pairs.