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.
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 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 & );
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;
}
}
How can I print the contents of a nested map? I am counting the number of times a word appears in a file, reporting it by line number and number of times per line. The words, lines, and occurrences per line are being stored in the following container:
map<string, map<int, int>> tokens;
However, I'm not sure on the syntax. I am printing the outer map that lists all of the words using the following code, but can't figure out how to print the inner values (the line number and number of times the word appears on each line) as well. I assume I can just include it inline in the for loop, but I can't figure out how:
for (map <string, map<int, int>>::iterator it = tokens.begin(); it != tokens.end(); ++it){
cout << it->first << " : " << /* assume I can include another statement here to print the values? */ endl;
}
I am trying to get an output similar to this:
(word : line:occurrences, line:occurrences, ...)
about : 16:1, 29:1, 166:1, 190:1, 191:1
above : 137:1
accompanied : 6:1
across : 26:1
admit : 20:1
advancing : 170:1
.
.
.
It is actually pretty simple.
You just get the internal map with it->second, and you iterate through that the same way.
Thereby, you would write something like this:
for (map <string, map<int, int>>::iterator it = tokens.begin(); it != tokens.end(); ++it){
cout << it->first << " : ";
map<int, int> &internal_map = it->second;
for (map<int, int>::iterator it2 = internal_map.begin(); it2 != internal_map.end(); ++it2){
if (it2 != internal_map.begin())
cout << ",";
cout << it2->first << ":" << it2->second;
}
cout << endl;
}
You could write something like this if you have C++11 support:
for (auto it : tokens) {
cout << it->first << " : ";
map<int, int> &internal_map = it->second;
for (auto it2: internal_map) {
if (it2 != internal_map.begin())
cout << ",";
cout << it2->first << ":" << it2->second;
}
cout << endl;
}
C++17
Since C++17 you can use range-based for loops together with structured bindings for iterating over maps.
This way, the readability of lpapp's C++11 solution can be further improved as follows:
for (auto const &[k1, v1] : tokens) {
std::cout << k1 << " : ";
for (auto const &[k2, v2] : v1) {
if (&k2 != &v1.begin()->first)
std::cout << ", ";
std::cout << k2 << ":" << v2;
}
std::cout << std::endl;
}
Note: I admit, the check for printing a comma is a bit messy. If you are looking for a nicer solution, you
might want to take a look at this Q&A.
Code on Coliru
Since we are only printing the elements, not modifying it, I would make more use of const, (a) const reference and (b) const iterators.
Also, for pre-C++11, it helps to define typedef's for complex types.
#include <string>
#include <map>
#include <iostream>
using namespace std;
typedef map<int, int> InnerMap;
typedef map<string, InnerMap> OuterMap;
void printClassic( OuterMap const & tokens ) {
for( OuterMap::const_iterator cit = tokens.begin();
cit != tokens.end(); ++cit ) {
cout << cit->first << " : ";
InnerMap const & imap = cit->second;
for( InnerMap::const_iterator cit2 = imap.begin();
cit2 != imap.end(); ++cit2 ) {
cout << cit2->first << ":" << cit2->second << ",";
}
cout << endl;
}
}
void printCpp11( OuterMap const & tokens ) {
for( auto const & cit : tokens ) {
cout << cit.first << " : ";
auto const & imap = cit.second;
for( auto const & cit2 : imap ) {
cout << cit2.first << ":" << cit2.second << ",";
}
cout << endl;
}
}
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;