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;
}
Related
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 just started to code in C++, so i'm new to STL .
Here i'm trying to iterate over a graph stored as vector of vectors.
#include <iostream>
#include <vector>
#include <iostream>
using namespace std;
int reach(vector<vector<int> > &adj, int x, int y) {
vector<vector<int> >::iterator it;
vector<int>::iterator i;
for (it = adj.begin(); it != adj.end(); it++)
{
cout << (*it) << endl;
if ((*it) == x)
for (i = (*it).begin(); i != (*it).end(); i++)
{
cout << (*i) << endl;
if ((*i) == y)
return 1;
}
}
return 0;
}
int main()
{
}
I'm getting an error std::vector<int> is not derived from const gnu cxx. Can someone point me in the right direction ?
*it pointing to vector not int that is why you are getting error
following code may work for you
#include <vector>
#include <iostream>
using namespace std;
int reach(vector<vector<int> > &adj, int x, int y) {
vector<vector<int> >::iterator it;
vector<int>::iterator i;
for (it = adj.begin(); it != adj.end(); it++)
{
cout << (*(*it).begin()) << endl;
if (( (*(*it).begin())) == x)
for (i = (*it).begin(); i != (*it).end(); i++)
{
cout << (*i) << endl;
if ((*i) == y)
return 1;
}
}
return 0;
}
int main()
{
}
for accessing first element of the vector of the use
(*(*it).begin()) in place of (*it)
if you are studying graph then use array of vector. for more details please go through following url
C++ Depth First Search (DFS) Implementation
cout << (*it) << endl;
Here, you declared it as a:
vector<vector<int> >::iterator it;
Therefore, *it is a:
vector<int>
So you are attempting to use operator<< to send it to std::cout. This, obviously, will not work. This is equivalent to:
vector<int> v;
cout << v;
There is no operator<< overload that's defined for what cout is, and a vector<int>. As you know, in order to print the contents of a vector, you have to iterate over its individual values, and print its individual values.
So, whatever your intentions were, when you wrote:
cout << (*it) << endl;
you will need to do something else, keeping in mind that *it here is an entire vector<int>. Perhaps your intent is to iterate over the vector and print each int in the vector, but you're already doing it later.
Similarly:
if ((*it) == x)
This won't work either. As explained, *it is a vector<int>, which cannot be compared to a plain int.
It is not clear what your intentions are here. "Graph stored as a vector or vectors" is too vague.
The following code compiles with the option std=c++11. But x is missing in vector<vector<int>>. If adj had type vector<pair<int, vector<int>>> it would better match.
The following code compiles for vector<vector<int>> but it doesn't use x.
using std::vector;
using std::pair;
using std::cout;
using std::endl;
int reach(vector<vector<int> > &adj, int x, int y) {
vector<vector<int> >::iterator it;
vector<int>::iterator i;
for(it=adj.begin();it!=adj.end();it++)
{
// cout << (*it) << endl;
for (const auto& nexts: *it)
cout << nexts << ' ';
cout << endl;
for(i=(*it).begin();i!=(*it).end();i++)
{
cout << (*i) << endl;
if((*i)==y)
return 1;
}
}
return 0;
}
This code compiles with <vector<pair<int, vector<int>>> and uses x.
using std::vector;
using std::pair;
using std::cout;
using std::endl;
int reach(vector<pair<int, vector<int> > > &adj, int x, int y) {
vector<pair<int, vector<int> > >::iterator it;
vector<int>::iterator i;
for(it=adj.begin();it!=adj.end();it++)
{
cout << it->first << endl;
if (it->first == x)
for(i=it->second.begin();i!=it->second.end();i++)
{
cout << (*i) << endl;
if((*i)==y)
return 1;
}
}
return 0;
}
Wrap it up in an iterator.
This can be templated for reuse.
Here is a minimal working example for the std::vector<T> container:
#include <iostream>
#include <utility>
#include <vector>
/// Iterable vector of vectors
/// (This just provides `begin` and `end for `Vector2Iterable<T>::Iterator`).
template<typename T>
class VovIterable
{
public:
static const std::vector<T> EMPTY_VECTOR;
/// Actual iterator
class Iterator
{
typename std::vector<std::vector<T>>::const_iterator _a1;
typename std::vector<T>::const_iterator _a2;
typename std::vector<std::vector<T>>::const_iterator _end;
public:
/// \param a1 Outer iterator
/// \param a2 Inner iterator
/// \param end End of outer iterator
explicit Iterator(typename std::vector<std::vector<T>>::const_iterator a1, typename std::vector<T>::const_iterator a2, typename std::vector<std::vector<T>>::const_iterator end)
: _a1(a1)
, _a2(a2)
, _end(end)
{
Check();
}
bool operator!=(const Iterator &b) const
{
return _a1 != b._a1 || _a2 != b._a2;
}
Iterator &operator++()
{
++_a2; // Increment secondary
Check();
return *this;
}
const T &operator*() const
{
return *_a2;
}
private:
void Check()
{
while (true)
{
if (_a2 != _a1->end()) // Is secondary live?
{
break;
}
// Increment primary
_a1++;
if (_a1 == _end) // Is primary dead?
{
_a2 = EMPTY_VECTOR.end();
break;
}
_a2 = _a1->begin(); // Reset secondary
}
}
};
private:
std::vector<std::vector<T>> _source;
public:
explicit VovIterable(std::vector<std::vector<T>> source)
: _source(std::move(source))
{
}
/// Start of vector of vectors
[[nodiscard]] Iterator begin() const
{
if (this->_source.empty())
{
return end();
}
return Iterator(this->_source.cbegin(), this->_source.cbegin()->cbegin(), this->_source.cend());
}
/// End of vector of vectors
[[nodiscard]] Iterator end() const
{
return Iterator(this->_source.cend(), EMPTY_VECTOR.end(), this->_source.cend());
}
};
template<typename T>
const std::vector<T> VovIterable<T>::EMPTY_VECTOR = {0};
/// Sample usage
int main()
{
std::vector<std::vector<int>> myVov{{1, 2, 3},
{4, 5, 6},
{7, 8, 9}};
for (int i: VovIterable(myVov))
{
std::cout << i << std::endl;
}
return 0;
}
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.
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.