I have a top list that stores inner lists. I'm using the standard template library list template.
I am attempting to print the values of the inner lists.
The top list is "L" and the inner list is "I".
void ListofLists::dump()
{
list<list<IntObj>>::iterator itr;
for (itr = L.begin(); itr != L.end(); itr++)
{
list<IntObj>::iterator it;
for (it = I.begin(); it != I.end(); it++)
{
cout << *it << " ";
}
cout << endl << "End" << endl;
}
}
My IDE doesn't like the line cout << *it << " ";and I'm not really sure how to change it while having the program do what I want it to do, which is print the data inside of the lists.
It red underlined the “<<“ operator and says “no operator “<<“ matches these operands.”
Can someone help me as to why? I've looked and can't really find what I'm looking for. I'm not understanding something correctly. I know it is adding the data to the data structure correctly because my IDE enables me to view my locals.
Thanks to anyone who helps! Means a lot.
Try to use :
list<IntObj>::const_iterator i;
instead the one you are using to avoid compiling error.
The inner loop does not make sense.
If you want to use iterators then the function can be defined like
void ListofLists::dump() /* const */
{
for (list<list<IntObj>>::iterator itr = L.begin(); itr != L.end(); itr++)
{
for ( list<IntObj>::iterator it = itr->begin(); it != itr->end(); it++)
{
cout << *it << " ";
}
cout << endl << "End" << endl;
}
}
However it will be simpler to use the range-based for loop. For example
void ListofLists::dump() /* const */
{
for ( const auto &inner_list : L )
{
for ( const auto &item : inner_list )
{
cout << item << " ";
}
cout << endl << "End" << endl;
}
}
Take into account that you have to define the operator << for the class IntObj.
Its declaration should look like
std::ostream & operator <<( std::ostream &, const IntObj & );
Related
I am sorry if this has been asked before (It seems as though every question has been asked before but with the plethora of questions asked on stack overflow it is sometimes hard to find). I have created a map of maps and am attempting to access the data in the second map. However, this is giving me issues in that I am unable to do iter->second.first or iter->second.second. I am able to do iter->first and iter-> second, but iter-> second is just a map and I am attempting to get the values in the second. I currently have "iter-second[x]" (just trying to find different ways to access the values) but I'm sure there is an easier way to do this. Attached are images of my code, what the map looks like while debugging, and the map creation, if there is anything else you need please let me know.
When I create the map I am assigning the incoming vector of arrays to the first key (works great, then I am assigning an int variable "lineCount" that is keeping track of the lines that have been read in, then incrementing the value of the second key by one if it has already been found.
assigning key's and value code in map:
void Reggie::assignMap(std::vector <std::string> &incVector)
{
//std::string word;
for (int i = 0; i < incVector.size(); i++) {
wordMap[incVector[i]][lineCount] +=1;
}
}
printMap Code
void Reggie::printMap()
{
int nextLineCounter{ 0 };
for (std::map<std::string, std::map<int, int>>::iterator iter = wordMap.begin(); iter != wordMap.end(); iter++) {
//for (std::map<std::string, std::map<int, int>>::iterator secondIter = iter->second.begin(); iter != wordMap.end(); secondIter++) {
std::cout << iter->first << " (" << iter->second[2] << " : " << iter->second[1] << " )" << std::endl;
nextLineCounter++;
}
}
Creation of map of maps
std::map<std::string, std::map<int, int>, Compare>wordMap;
printMap debugging image
I'm a bit confused why you commented out the second loop. I mean it's wrong but surely you realise that you can't iterate through a map of maps with only one loop?
Here's the code corrected
for (std::map<std::string, std::map<int, int>>::iterator iter = wordMap.begin();
iter != wordMap.end();
iter++)
{
for (std::map<int, int>::iterator secondIter = iter->second.begin();
secondIter != iter->second.end();
secondIter++)
{
std::cout << iter->first <<
" (" << secondIter->first <<
" : " << secondIter->second <<
" )" << std::endl;
}
}
Of course it's code like this that auto was invented for
for (auto iter = wordMap.begin();
iter != wordMap.end();
iter++)
{
for (auto secondIter = iter->second.begin();
secondIter != iter->second.end();
secondIter++)
{
std::cout << iter->first <<
" (" << secondIter->first <<
" : " << secondIter->second <<
" )" << std::endl;
}
}
Or range based for loops were invented for
for (const auto& pair : wordMap)
{
for (const auto& secondPair : pair.second)
{
std::cout << pair.first <<
" (" << secondPair.first <<
" : " << secondPair.second <<
" )" << std::endl;
}
}
I am trying to display the contents of a multimap with a string and a vector as key and value, respectively. I run into problems when I try to dislpay the contents of the vector (value in multimap). What I have done so far is:
multimap<string, vector<string> > someMultimap;
vector<string> someVector;
someVector.push_back("test");
someMultimap.insert(pair<string, vector<string> >("KEY", someVector));
//So for it works fine...
multimap <string, vector<string> >::iterator it;
for (it = someMultimap.begin(); it != someMultimap.end(); ++it)
{
cout << it->first << endl << endl << it->second << endl << endl;
^^^^^^^^^^
this is the problem, can´t do this with a vector(?)
}
Does anyone have a suggestion for solving the problem?
You can add a second loop for the vector.
multimap <string, vector<string> >::const_iterator it;
for (it = someMultimap.begin(); it != someMultimap.end(); ++it)
{
cout << it->first << endl ;
vector<string>::const_iterator itVec;
for (itVec = it->second.begin(); itVec != it->second.end(); ++itVec)
{
cout << *itVec <<" ";
}
cout<<endl;
}
If you don't plan to modify any value you can make your iterators const
Use std::copy to output the vector's contents with a single function:
#include <iterator>
#include <algorithm>
#include <iostream>
//..
using namespace std;
for (it = someMultimap.begin(); it != someMultimap.end(); ++it)
{
cout << it->first << "\n\n";
copy(it->second.begin(), it->second.end(), ostream_iterator<string>(cout, " "));
cout << "\n\n";
}
Loop through the vector and print:
cout << it->first << endl << endl;
for (vector<string>::iterator j(it->second.begin()); j != it->second.end(); ++j)
cout << *j << " ";
cout << endl << endl;
Also, don't use std::endl, it flushes on each call which can hinder performance.
Well, you can define what it means to send a std::vector to a std::ostream.
Here's an example of one way to do it:
template<typename T>
std::ostream& operator <<(std::ostream& stream, std::vector<T> const& v) {
for (auto&& e : v) {
stream << e << ' ';
}
return stream;
}
Just a question, on the use of const_iterator vs just iterator. More specifically with the use of distance(). Below is some basic code that just craps out a list of "fav_games" that the user enters (earlier in the application). I wanted to also crap out the 'index' of the vector so as to print out a numbered list.
Partial Code:
int main()
{
vector<string> fav_games;
vector<string>::const_iterator iter; // const_iterator no worky with "distance()"
if (fav_games.size() > 0) {
cout << "\n\nCurrent game list: \n";
for (iter = fav_games.begin(); iter != fav_games.end(); ++iter)
{
cout << distance(fav_games.begin(), iter) << ". " << *iter << endl;
}
}
return 0;
}
My question is why, "const_iterator" will not work, where I am forced to use "iterator" instead. Looking for the 'theory' behind it. "distance()" appears to expecting and "iterator" -- not "const_iterator". ..Why?
Just for reference the compile error if I use "const_iterator":
Error 1 error C2782: 'iterator_traits<_Iter>::difference_type std::distance(_InIt,_InIt)' : template parameter '_InIt' is ambiguous z:\micah\c++\favgames\favgames\favgames.cpp 49 1 favgames
Thanks!
Try this instead:
vector<string>::const_iterator b, iter, e;
if (fav_games.size() > 0) {
cout << "\n\nCurrent game list: \n";
for (b = fav_games.begin(), iter = b, e = fav_games.end(); iter != e; ++iter)
{
cout << distance(b, iter) << ". " << *iter << endl;
}
}
distance has no problem with two const_iterator instances, or two iterator instances. Your mistake was in mixing them.
Still, making O(n) calls to distance is crazy. Just use a counter:
vector<string>::const_iterator iter, e;
size_t i;
if (fav_games.size() > 0) {
cout << "\n\nCurrent game list: \n";
for (i = 0, iter = fav_games.begin(), e = fav_games.end(); iter != e; (++iter), (++i))
{
cout << i << ". " << *iter << endl;
}
}
In C++11 and later, one may of course go one step further and avoid explicit use of the iterators at all:
if (fav_games.size() > 0) {
int i = 0;
cout << "\n\nCurrent game list: \n";
for (const string& game : fav_games)
{
cout << (i++) << ". " << game << endl;
}
}
I have this code
void Options::printHelp() {
hash_map<string, Option>::iterator iter;
for ( iter = options.begin(); iter != options.end(); iter++ ) { //<- this one
cout << iter->first;
cout << "\t";
cout << iter->second.getDescription() << "\n";
}
}
Definition of options
class Options {
...
hash_map<string, Option> options;
private:
....
}
XCode (Which is the IDE i’m using) marks the area "iter != options.end()" and gives me the error specified in the title.
I Can’t seem to figure out why.
(Option, btw, is a small container class, that holds 2 strings and an enum)
It's hard to say what exactly the problem is without seeing the definition of options. My guess is it's not of hash_map<string, Option> type.
If you write your code like the this though, you shouldn't be running into that sort of problems:
for ( auto iter = options.begin(), end = options.end(); iter != end; ++iter ) {
cout << iter->first;
cout << "\t";
cout << iter->second.getDescription() << "\n";
}
Or even better:
for ( auto &i: options )
cout << i.first << '\t' << i.second.getDescription() << '\n';
This requires C++11.
How to do the following in more stylish/short way?
for(i=container.begin(); i!=container.end(); ++i) {
if (i!=container.begin()) {
cout << ", ";
}
cout << *i;
j=i;
if (++j==container.end()) {
cout << "!" << endl;
}
}
Solutions like foreach are acceptable (actions on first and last elements need to be configurable, though).
P.S.
There are many answers that are handling first element, but not last. Here is what I mean by handling last element:
for(i=container.begin(); i!=container.end(); ++i) {
j=i;
if (i==container.begin()) {
cout << "[" << *i << "]" << endl;
} else if (++j==container.end()) {
cout << ", (" << *i << ")" << "!" << endl;
} else {
cout << ", " << *i;
}
}
Don't you think it's very easy to handle first element outside the cycle body? The real problem is the last one! I'm sorry for not being able to clarify the important point asking the question. I think I'll just accept the top ranked answer eventually.
Boost has next / prior which can sometimes help in such situations.
for(i=container.begin(); i!=container.end(); ++i) {
if (boost::next(i) == container.end()) {
std::cout << "!" << std::endl;
}
}
Although for this specific case, I'd simply output the first element, loop from second till last while always outputting the ',' and then output the '!' after the loop has ended. (as others have suggested already)
I don't see the point in moving the special cases inside the loop, and then checking inside the loop for them....
My advice here would be: there is no point in detecting anything within this loop !
Since your special cases are at the beginning and the end of your container, it is easy to remove their processing from within the loop.
The following function will print the contents of any container class whose elements can be <<'ed to an std::ostream:
template < class Container >
void print(Container const & container)
{
typename Container::const_iterator current = container.begin();
typename Container::const_iterator const end = container.end();
if (current != end)
{
std::cout << *current;
for (++current; current != end; ++current)
{
std::cout << ", " << *current;
}
std::cout << "!" << std::endl;
}
}
In your code,
if (i==container.end()) {
cout << "!" << endl;
}
will never happen.
My own approach would be to use the container size (I think size() is now constant time for all Standard Library containers). Maintain a count in the loop and you are at the end when count == size() - 1, and at the beginning when count == 0, obviously.
As container is not defined by you, I used the simplest - vector
template <class T>
string vector_join( const vector<T>& v, const string& token ){
ostringstream result;
for (typename vector<T>::const_iterator i = v.begin(); i != v.end(); i++){
if (i != v.begin()) result << token;
result << *i;
}
return result.str();
}
//usage
cout << vector_join( container, ", " ) << "!";
Shift the ++i a bit:
i = container.begin();
while(i != container.end()) {
if (i != container.begin()) {
cout << ", ";
}
cout << *i;
if (++i == container.end()) {
cout << "!" << endl;
}
}
template < class TContainerType>
void print(TContainerType const & i_container)
{
typename TContainerTypeconst ::const_iterator current = i_container.begin();
typename TContainerTypeconst ::const_iterator const end = i_container.end();
if(current != end)
{
std::cout << *current++;
while(current != end)
std::cout << ", " << *current++;
}
std::cout << "!" << std::endl;
}
Take the second part out of the loop.
for(i=container.begin(); i!=container.end(); ++i) {
if (i != container.begin()) {
cout << ", ";
}
cout << *i;
}
cout << "!" << endl;