How do I iterate over this C++ vector?
vector<string> features = {"X1", "X2", "X3", "X4"};
Try this:
for(vector<string>::const_iterator i = features.begin(); i != features.end(); ++i) {
// process i
cout << *i << " "; // this will print all the contents of *features*
}
If you are using C++11, then this is legal too:
for(auto i : features) {
// process i
cout << i << " "; // this will print all the contents of *features*
}
C++11, which you are using if this compiles, allows the following:
for (string& feature : features) {
// do something with `feature`
}
This is the range-based for loop.
If you don’t want to mutate the feature, you can also declare it as string const& (or just string, but that will cause an unnecessary copy).
Related
vector<vector<string> > vvs;
vector<string> vs;
vs.push_back("r1-c1");
vs.push_back("r1-c2");
vs.push_back("r1-c3");
vvs.push_back(vs);
for (vector<vector<string> >::iterator vvsi = vvs.begin(); vvsi != vvs.end(); vvsi++) {
vector<string> vec_str = *vvsi;
for (vector<string>::iterator vsi = vec_str.begin(); vsi != vec_str.end(); vsi++) {
cout << *vsi << ", ";
}
cout << "\n";
}
In the above C++ code, to avoid the copy of vector(vector vec_str = *vvsi) i tried the below code
vector<string> *vec_str = vvsi.base(); //Working. which (returns a const pointer&)
vector<string> *vec_str = &(*vvsi); //Working. Assigning the address
But
vector<string> *vec_str = vvsi; //Error. Not able to assign
Error
(build error : cannot convert 'std::vector<std::vector<std::basic_string<char> > >::iterator to 'std::vector<std::basic_string<char> >*' in initialization)
In a case of integer
int a=10;
int *b = &a; //working. Assigning address
int *c = &(*b); //working. Assigning address
int *d = b; //working. Assigning address
*c=11;
std::cout << a<<"\n";
*d=12;
std::cout << a<<"\n";
In the case of vector, why the build error when assigning (can't able to understand from the C++ iterator documentation)?
An iterator is not a pointer. It's interface was made to be used as a pointer, but it certainly is not a pointer.
However, if you simply want to iterate through the elements of each vector in the parent vector, there is no need to assign it to a temporary vector or to a pointer, the iterator itself is good enough:
for (vector<vector<string> >::iterator vvsi = vvs.begin(); vvsi != vvs.end(); ++vvsi) {
for (vector<string>::iterator vsi = vvsi->begin(); vsi != vvsi->end(); ++vsi) {
cout << *vsi << ", ";
}
cout << "\n";
}
Also, since you put c++11 as a tag in your question, I assume you might be interested in a more modern expression:
for(auto& vst : vvs){
for(auto& st : vst){
cout << st << ", ";
}
cout << endl;
}
You're trying to assign the value of an iterator to a pointer. That the iterator points to the same type as the pointer is irrelevant, since RandomAccessIterators, which are the iterator type of std::vector, are not implicitly convertible to pointers.
If you're using c++11, there are simpler ways to go about iterating over a vector of a vector even than #A Hernandez's solution (or any container of containers at that), using the range-for syntax available in c++14:
for(auto &&stringVec : vvs){
for(auto &&str : stringVec){
cout << str << ", ";
}
}
cout << '\n';
The && here allows binding to temporary containers as well as existing ones, so you can use this syntax with both existing container containers and container containers returned from a function without storing them.
Pretty new to C++, only at it a week or so, I want to iterate through a set of nested sets and write each element in the inner set to a line in a file.
Each inner set has 3 elements and I want all three elements on the same line.
I have a set up as follows:
// Define "bigSet" and initiate as empty set "Triplets"
typedef set < set<string> > bigSet;
bigSet Triplets;
I tried something of this sort to go through it but it gives me an error...
// Iterate through and print output
set <string>::iterator it;
for(it = Triplets.begin(); it != Triplets.end(); it++){
cout << *it << endl;
}
Any help is greatly appreciated guys thank you!
I would do it this way:
// Iterate through and print output
set < set <string> >::iterator it_ex; // iterator for the "outer" structure
set <string>::iterator it_in; // iterator for the "inner" structure
for(it_ex = Triplets.begin(); it_ex != Triplets.end(); it_ex++)
{
for(it_in = it_ex->begin(); it_in != it_ex->end(); it_in++)
cout << *it_in << ", ";
cout << endl;
}
Triplets is not a set<string>; it is a set<set<string>>; each item in Triplets is itself a set, than can contain several strings.
The iterator must match the type of the container; with two levels of nested containers, you should iterate twice:
set<set<string>>::iterator it;
set<string>::iterator it2;
for(it = Triplets.begin(); it != Triplets.end(); it++) {
for (it2 = it->begin(); it2 != it->end(); ++it2) {
cout << *it2 << endl;
}
}
Triplets is type set < set<string> > and therefore requires an iterator of type set < set<string> >::iterator or bigSet::iterator. It isn't type set <string>. You could also use const_iterator.
Note that iterating Triplets gives you an iterator to another set, and not a string.
Also consider
for (const auto& i : Triplets)
{
for (const auto& j : i)
{
cout << j << endl;
}
}
You have an error because Triplets.begin() is not of type set<string>::iterator, it's set<set<string>>::iterator.
What you need to do is have two loops: one for iterating over the outer set and one for the inner.
set<set<string>>::iterator it;
for(it = Triplets.begin(); it != Triplets.end(); ++it)
{
set<string>::iterator it2;
for(it2 = it->begin(); it2 != it->end(); ++it2)
{
cout << *it2;
}
cout << endl;
}
If you use increment/decrement operators (++/--) on iterators, it might be better to use the prefix versions (++it) instead of the suffix ones (it++). This is because the suffix ones create a copy of the iterator before it is incremented (and that copy is then returned) but in cases like this, you have no need for it.
Moreover, if you're using C++11, you can use the range-based for loops and auto keyword, which simplify things a lot:
for(const auto &innerSet : Triplets)
{
for(const auto &innerSetElement : innerSet)
{
cout << innerSetElement;
}
cout << endl;
}
First: if they're triplets, are you sure that std::set is the type you
want for the inner values. Perhaps a class would be more
appropriate, in which case, you define an operator<< for the `class,
and your simple loop works perfectly. Something like:
class Triplet
{
std::string x;
std::string y;
std::string z;
public:
// Constructors to enforce that none of the entries are identical...
// Accessors, etc.
friend std::ostream& operator<<( std::ostream& dest, Triplet )
{
dest << x << ", " << y << ", " << z;
return dest;
}
};
And then to output:
for ( Triplet const& elem : Triplets ) {
std::cout << elem << std::endl;
}
Otherwise: you need to define the format you want for the output. In
particular, you'll probably want a separator between the strings in the
line, for example. Which means you probably cannot use a range based
for, at least not for the inner loop. You would need something like:
for ( std::set<std::string> const& triplet : Triplets ) {
for ( auto it = triplet.cbegin(); it != triplet.cend(); ++it ) {
if ( it != triplet.cebegin() ) {
std::cout << ", ";
}
std::cout << *it;
}
std::cout << std::endl;
}
(If the set of triplets is large, you'll definitely want to consider
replacing std::endl with '\n'. But of course, if it is really
large, you probably won't be outputting to std::cout.)
is there a possibility to use difference_type with std::distance in the BOOST_FOREACH loop?
#define foreach_ BOOST_FOREACH
class iObj { /* some def and impl */ };
typedef set<iObj*> iSet;
int main() {
iSet *iobjs = new iSet();
// fill set with integers
for( int i=0; i<100; i++) {
iobjs->insert( new iObj(i+1+i*2) );
}
// output content of set
cout << "print objects ASC" << endl;
for( iSet::const_iterator oIt = iobjs->begin();
oIt != iobjs->end(); ++oIt) {
iSet::difference_type oIndex = std::distance( iobjs->begin(), oIt );
if( oIndex < 50 ) {
cout << " #" << oIndex << ": " << **oIt << endl;
} else {
break;
}
}
// output with BOOST
cout << "print objects ASC" << endl;
foreach_( iObj *o, *iobjs ) {
cout << *o << endl;
// no access of index?
}
delete iobjs;
return 0;
}
it is more convenient to display e.g. the first 50 entries of a big set, not the whole content and with std::distance it is not necessary to insert a new counter var and increment it by myselfe
You want to know the loop iteration from within the body of a BOOST_FOREACH loop? No, you can't do that. You can't do it with a C++11 range-based for loop, either. For this purpose, the ordinary for loop is best. (And please, please, please stop using BOOST_FOREACH. C++11's range-based for is the final word on the subject.)
I should also point out that your code is needlessly inefficient. std::set's iterators are not random-access, so std::distance is O(N). Far better is to keep a separate loop counter, and simply increment it each time through the loop.
Also, your code is leaking memory. Although you are deleting the std::set you have new'ed, you're not deleting all the iObj objects you've new'ed. It doesn't seem like there is any need to be dynamically allocating anything in the code you've shown. Try just storing objects by value instead of new'ing them, and use a local std::set stack variable too. You'll save yourself a world of trouble.
Given the minimal C++11 STL example:
set<int> S = {1,2,3,4};
for(auto &x: S) {
cout << x;
cout << ",";
}
Is there a way to check if x is the one right before the end? The goal in this example is to output 1,2,3,4 and not the final comma at the end. Currently I use a standard for loop with two iterators,
set<int>::const_iterator itr;
set<int>::const_iterator penultimate_end_itr = --S.end();
for(itr=S.begin(); itr!=penultimate_end_itr;++itr)
cout << (*itr) << ',';
cout << (*penultimate_end_itr);
Which works, but is terribly cumbersome. Is there a way to do the check within the range-based for loop?
EDIT: The point of the question is not to print out a comma separated list. I want to know if a range-based for loop has any knowledge of the penultimate element in the list (i.e. is it one before the end). The minimal example was presented so we all have a common code block to talk about.
The very purpose of range-based for loops is to forget the iterator. As such, they only allow you access to the current value and not the iterator. Would the following code do it for you?
set<int> S = {1,2,3,4};
std::string output;
for(auto &x: S) {
if (!output.empty())
output += ",";
output += to_string(x);
}
cout << output;
EDIT
Another solution: Instead of comparing iterators (as one would do with "normal" for loops), you could compare the addresses of the values:
set<int> S = {1,2,3,4};
auto &last = *(--S.end());
for (auto &x : S)
{
cout << x;
if (&x != &last)
cout << ",";
}
Boost.Range can help out here:
if (std::begin(S) != std::end(S)) {
std::cout << *std::begin(S);
for (const auto &x: boost::make_iterator_range(std::next(std::begin(S)), std::end(S))) {
std::cout << ", " << x;
}
}
A much more flexible approach is to index the range, using boost::adaptors::indexed (since Boost 1.56):
for (const auto &element: boost::adaptors::index(S)) {
std::cout << (element.index() ? ", " : "") << element.value();
}
In versions of Boost prior to 1.56 boost::adaptors::indexed won't work but you can easily write a work-alike:
template <typename... T>
auto zip(const T&... ranges) -> boost::iterator_range<boost::zip_iterator<decltype(boost::make_tuple(std::begin(ranges)...))>>
{
auto zip_begin = boost::make_zip_iterator(boost::make_tuple(std::begin(ranges)...));
auto zip_end = boost::make_zip_iterator(boost::make_tuple(std::end(ranges)...));
return boost::make_iterator_range(zip_begin, zip_end);
}
template<typename T>
auto enumerate(const T &range) -> boost::iterator_range<boost::zip_iterator<boost::tuple<
boost::counting_iterator<decltype(boost::distance(range))>, decltype(std::begin(range))>>>
{
return zip(boost::make_iterator_range(boost::make_counting_iterator(0),
boost::make_counting_iterator(boost::distance(range))), range);
}
for (const auto &tup: enumerate(S)) {
std::cout << (tup.get<0>() ? ", " : "") << tup.get<1>();
}
This is using the zip function from Sequence-zip function for c++11?
I have a Playlist class that has a vector with Tracks and each Track has a multimap<long, Note> as datamember.
class Track {
private:
multimap<long, Note> noteList;
}
Using an iterator to acces the tracks is no problem, so this part here is working fine:
vector<Track>::iterator trackIT;
try{
for(noteIT = trackIT->getNoteList().begin(); noteIT != trackIT->getNoteList().end(); noteIT++){
cout << "---" << noteIT->second.getName() << endl;
}
}catch (int e){
cout << "exception #" << e << endl;
}
What I want to do next is iterate the Notes of each Track. But starting from this part all output is stopped. So I only get to see the first tracks name. Any cout's after that are not shown and the compiler isn't giving me any errors. Even the cout inside the try catch block isn't working..
vector<Track>::iterator trackIT;
multimap<long, Note>::iterator noteIT;
for(trackIT = this->playlist.getTracklist().begin(); trackIT < this->playlist.getTracklist().end(); trackIT++){
cout << trackIT->getTrackName() << endl;
for(noteIT = trackIT->getNoteList().begin(); noteIT != trackIT->getNoteList().end(); noteIT++){
cout << "---" << noteIT->second.getName() << endl;
}
}
cout << "random cout that is NOT shown" << endl; // this part doesn't show up in console either
Also, the method in my Track class that I'm using to add the Note objects looks like this:
void Track::addNote(Note ¬e) {
long key = 1000009;
this->noteList.insert(make_pair(key, note));
}
// I'm adding the notes to the track like this:
Note note1(440, 100, 8, 1, 1);
note1.setName("note1");
synthTrack.addNote(note1);
Any ideas why the iterator won't work?
Change
noteIT < trackIT->getNoteList().end()
To
noteIT != trackIT->getNoteList().end()
Not all iterators support less than / greater than comparisons.
If you have c++11 you can use a range-based for loop:
for (Note& note : trackIT->getNoteList())
Or you can use BOOST_FOREACH
BOOST_FOREACH (Note& note, trackIT->getNoteList())
You haven't shown the definitions of getTrackList or getNoteList, but there's a common mistake people make - if you return a copy of the container instead of a reference to it, the iterators will be pointing to different containers making comparisons impossible. Not only that but since the containers are temporary any use of the iterators results in undefined behavior.
If you are really hardcoding the track key, then there will only ever be one track in the map because std::map stores unique keys...
long key = 1000009; //If yo are really doing this, this key is already inserted so it will fail to insert more.
Also, if you would like a more elegant approach you could use function object.
struct print_track
{
void operator()(const Track& track)
{
cout << track.getTrackName() << endl;
std::for_each(track.getNoteList().begin(), track.getNoteList().end(), print_track_name());
}
};
struct print_note_name
{
void operator()(const std::pair<long,Note>& note_pair)
{
cout << "---" << note_pair.second.getName() << endl;
}
};
//In use...
std::for_each(playlist.getTracklist().begin(), playlist.getTracklist.end(), print_track());