C++ Maps

Hi, I am having difficultly understanding how to print the value of the vector inside a map.
1
2
3
4
5
6
7
8
9
10
map<string,vector<string> > test;

 map<string,vector<string> >::iterator itr;
    for(itr = test.begin(); itr != test.end(); itr++)
    {
        for(int i = 0; i != itr->second.size(); i++)
        {
            cout << itr->second[i] << endl;
        }
    }

This is what I have but it just seem strange. Is their a better method?
You could use iterators for vectors too:

1
2
3
4
5
for (vector<string>::const_iterator vi = itr->second.begin();
    vi != itr->second.end();
    ++vi
    )
    cout << *vi << endl;


If you're using Visual Studio 2010+, or GNU GCC 4.6+, they may offer support for C++11's range based for loop, and automatic type inference.

Then your code could look like:
1
2
3
4
5
map<string, vector<string> > test;

for (auto aPair: test)
    for (string s: aPair.second)
        cout << s << endl;


Disclaimer: code not tested, yet.
Unfortunately, range-based fors didn't turn up with Visual Studio 2010. But they are there in 2012.
Last edited on
So it would always have to be a nested loop in order to get the value in the vector?
Well, yes. But the loops don't have to actually be nested, or even your own. For example, you could factor out the vector output code into a helper function?

1
2
3
4
5
6
7
8
template<typename TElem>
inline void write_vector(ostream& os, const vector<TElem>& vec) {
	typedef vector<TElem>::size_type size_type;
	const size_type size = vec.size();
	for(size_type i = 0; i < size; ++i) {
		os << vec[i] << endl;
	}
}


and then use it like

1
2
3
4
	typedef map<string,vector<string> >::iterator iter_type;
	for(iter_type itr = test.begin(), itr_end = test.end(); itr_end != itr; ++itr) {
		write_vector(cout, itr->second);
	}


or use an algorithm

1
2
3
4
5
6
	typedef map<string, vector<string> >::iterator iter_type;
	for(iter_type itr = test.begin(), itr_end = test.end(); itr_end != itr; ++itr) {
		const vector<string>& vec = itr->second;
		ostream_iterator<string> out_it(cout, "\n");
		copy( vec.begin(), vec.end(), out_it);
	}


or even use a iterative solution?

1
2
3
4
5
6
7
template<typename TIter>
inline void write_iteratively(TIter itr, const TIter itr_end, ostream& os) {
	if(itr != itr_end) {
		os << *itr << endl;
		write_iteratively(itr + 1, itr_end, os);
	}
}


used like this

1
2
3
4
5
	typedef map<string, vector<string> >::iterator iter_type;
	for(iter_type itr = test.begin(), itr_end = test.end(); itr_end != itr; ++itr) {
		const vector<string>& vec = itr->second;
		write_iteratively(vec.begin(), vec.end(),cout);
	}

Last edited on
... well you could use the horrible std::for_each() from the algorithm library, together with C++11 lambdas.

(Prepare a barf bag.)

1
2
3
4
5
6
7
8
9
10
11
#include <algorithm>

// ...

for_each(test.begin(), test.end(), [](decltype(*test.begin()) aPair) {
    for_each(aPair.second.begin(), aPair.second.end(), [](string s) {
        cout << s << ' ';
    });

    cout << endl;
});

Thank You all for the help I understand it now.
Topic archived. No new replies allowed.