1

I am having a map like this

typedef vector< pair<int, string> > Categories;  
map<string,Categories> cats;

but when I am trying to read elements of the map like

for(map<string,Categories>::const_iterator it = cats.begin(); it != cats.end(); ++it)
 {
    std::cout << it->first << " "  << it->second.first<<"\n";
 }

I do get errors

error: 'const class std::vector<std::pair<int, std::basic_string<char>
' has no member named 'first'  std::cout << it->first << " "  << it-> second.first<<"\n";
3
  • 3
    @tkausl You mean "it->second is a vector, not a pair." Commented May 13, 2018 at 18:56
  • 1
    Oh right, I forgot that you iterate over key-value pairs, not values. Commented May 13, 2018 at 18:57
  • 3
    What in the error message is not understandable? Did you lose track of the definitions you set up? Commented May 13, 2018 at 19:02

4 Answers 4

2

error: 'const class std::vector ' has no member named 'first' std::cout << it->first << " " << it->second.first<<"\n";

Its clear as Crystal, that you might have many elements in your values of your map, which is a std::vector< std::pair<int, std::string>>

Then how would you print elements of a vector? The options are:

  1. random access (i.e, vec[index])
  2. iterator (i.e, std::vector< std::pair<int, std::string>>::const_iterator itr;)
  3. or by a range based for loop (i.e, for(const auto& it: vec) )

In your case, if you wanna have something simple and easy code is using a range based loop:

   for(const auto& it: cats)
   {
      std::cout << it.first << " = "; // keys
      for(const auto& ve: it.second)  // values vec
         std::cout << ve.first << "-" << ve.second << "\t";
      std::cout << std::endl;
   }

If you still wanna have long iterator loops, here is it.

see live action here: https://www.ideone.com/3bS1kR

#include <string>
#include <iostream>
#include <vector>
#include <map>
#include <iterator>

typedef std::vector< std::pair<int, std::string>> Categories;

int main()
{
   std::map<std::string, Categories> cats;

   cats["key1"] = {std::make_pair(1, "pair1"), std::make_pair(1, "pair2"), std::make_pair(1, "par3")};
   cats["key2"] = {std::make_pair(2, "pair1"), std::make_pair(2, "pair2")};
   cats["key3"] = {std::make_pair(3, "pair1")};

   std::cout << "Range based loop \n";
   for(const auto& it: cats)
   {
      std::cout << it.first << " = ";  // keys
      for(const auto& ve: it.second)   // values vec
         std::cout << ve.first << "-" << ve.second << "\t";
      std::cout << std::endl;
   }

   std::cout << "\nIterator loop \n";
   std::map<std::string, Categories>::const_iterator it;
   std::vector< std::pair<int, std::string>>::const_iterator curr_val_it;
   for(it = cats.cbegin(); it != cats.cend(); ++it)
   {
      std::cout << it->first << " = "; // keys

      for(curr_val_it = it->second.cbegin(); curr_val_it != it->second.cend(); ++curr_val_it )
          std::cout << curr_val_it->first << "-" << curr_val_it->second << "\t";  // values vec

      std::cout << std::endl;
   }


   return 0;
}
Sign up to request clarification or add additional context in comments.

1 Comment

@Just_Newbie: if you are looking for the first element of category of key = key1; this is the solution: std::cout << cats["key1"][0].first << " " << cats["key1"][0].second <<"\n";
1

you need to access a element of the vector first, then the pair within.

... it->second[0].first<< ...

better impl of loop:

for(const auto& cat : cats)
 {
     string mapidx = cat.first;
     vector<pair<int, std::string>> catvect = cat.second;
 }

then you can have a seperate loop to read the contents of the vector:

for(const auto& cat : cats)
 {
     string mapidx = cat.first;
     vector<pair<int, std::string>> catvect = cat.second;
     for (const auto& entry : catvect)
     {
         int number = entry.first;
         string whatever = entry.second;
     }
 }

the temp variables are just for readability, no need for all the copies ;)

1 Comment

You could turn the temp variables into (const) references to avoid the copies while keeping the readability.
1

Error is exacly what compiler told you:

const class std::vector ' has no member named 'first'

so, you have do decide how to print your map by overloading ostream opeartor, below example how it can be achived:

#include <iostream>
#include <map>
#include <string>
#include <utility>
#include <vector>

typedef std::vector<std::pair<int, std::string>> Categories;  
std::map<std::string,Categories> cats;

std::ostream& operator << (std::ostream& os, const std::vector<std::pair<int, std::string>>& v) 
{
    os << "[";
    for (auto& el : v) {
        os << " " << el.first << " : " << el.second;
    }
    os << "]";
    return os;
}

int main() {
    cats.emplace("cat1", std::vector<std::pair<int, std::string>>(1, std::make_pair(1, "category1")));
    for(auto& cat : cats) {
        std::cout << cat.first << " "  << cat.second << "\n";
    }
}

Comments

0

Since we are storing Vector Categories inside a Map we will have to iterate Vector too:

 for(map<string,Categories>::const_iterator it = cats.begin(); it != cats.end(); ++it)
    {
        //iterator for vector (it->second)
        for(Categories::const_iterator it2 = it->second.begin(); it2 != it->second.end(); it2++ )
        {
              std::cout << it->first << " "  << it2->first<<" "<<it2->second <<"\n";
        }
    }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.