How to insert and iterate elements to this kind of map. C++ - c++

I tried on my own. But I was unable to do it. So, please help.
unordered_map<string, pair<string , vector<int>>> umap;
Or more precisely, how We can make pair of one string and one vector that can be used in map.

Well you can use insert function and insert them as a pair (Or precisely nested pairs).
For example Checkout this program :
#include <iostream>
#include <vector>
#include <string>
#include <unordered_map>
using namespace std;
int main()
{
unordered_map<string, pair<string , vector<int>>> umap;
//Insert like this
umap.insert(make_pair("first", make_pair("data1",vector<int>(3, 0))));
umap.insert(make_pair("second", make_pair("data2",vector<int>(3, 1))));
//or like this
string s = "new", t= "method";
vector <int> v = {1, 2, 3};
umap.insert(make_pair(s, make_pair(t, v)));
//This will print all elements of umap
for(auto p : umap)
{
cout << p.first << " -> " << p.second.first << " , VECTOR : " ;
for(auto x : p.second.second)
cout << x << ',';
cout << endl;
}
cout << endl;
//Let's see how to change vector already inside map
auto itr = umap.begin();
cout << "BEFORE : ";
for(auto x : (itr->second).second)
{
cout << x << ',';
}
cout << endl;
//We will push 42 here
(itr->second).second.push_back(42);
cout << "AFTER : ";
for(auto x : (itr->second).second)
{
cout << x << ',';
}
cout << endl;
}
Output Is :
new -> method , VECTOR : 1,2,3,
second -> data2 , VECTOR : 1,1,1,
first -> data1 , VECTOR : 0,0,0,
BEFORE : 1,2,3,
AFTER : 1,2,3,42,
I hope this helps.

This depends a lot on the complexity of what you are creating. For example, if you have some constants in your vector, you could make them in place:
umap.emplace("s", std::make_pair("s2", std::vector<int>{1, 2, 3, 4}));
It is more likely however that you will be making the internals in some complex way. In which case you could more easily do it as separate constructions.
std::vector<int> values;
values.push_back(1);
auto my_value = std::make_pair("s2", std::move(values));
umap.emplace("s2", std::move(my_value));
Using move to move the data around ensures minimal copying.
Finally, to iterate the items, it is normal to use range-based for loops:
for (const auto& [key, value]: umap) {
std::cout << key << ": ";
const auto& [name, values] = value;
std::cout << name << " {";
for (auto val : values) {
std::cout << val << " ";
}
std::cout << "}\n";
}
Here you can check out a live example.

Related

How can I change map 's second component?

#include <iostream>
#include <map>
using namespace std;
int main() {
map<int, int> ma;
// 원소를 추가 하자!!
ma.insert(make_pair(100, 2)); // key 값 : 1 , value : 3
ma.insert(make_pair(101, 3)); // key 값 : 3, value : 13
ma.insert(make_pair(102, 2)); // key 값 : 3, value : 13
ma.insert(make_pair(103, 3)); // key 값 : 3, value : 13
ma.insert(make_pair(104, 1)); // key 값 : 3, value : 13
// make_pair 형식으로 저장 했으므로
// key 값은 fisrt 로 접근 value 값은 second 로 접근한다.
for (auto iter : ma) {
cout << "key : " << iter.first << " value : " << iter.second << '\n';
iter.second = iter.second + 1;
}
cout << "\n" << "\n";
for (auto iter : ma) {
cout << "key : " << iter.first << " value : " << iter.second << '\n';
}
cout << "\n" << "\n";
return 0;
}
Actually , I want to change the value of second component of pair.
iter.second = iter.second + 1;
This code can't change the thing...
How can I change ???
The auto keyword in C++ always tries to infer a non-reference type, so in your case it infers iter as being type std::pair<const int, int>. This is not a reference type, so the values from the map get copied into the iter variable, and so any changes made to iter are not reflected in the map itself.
You can write auto& instead to force an lvalue-reference type:
for (auto& iter : ma) { // <-- Notice ampersand here
iter.second = iter.second + 1;
}
Your main problem is that you called the variable "iter" so you must think it is an iterator of some sort. If it were an iterator, your code would work fine:
#include <iostream>
#include <map>
int main() {
std::map<int, int> map {
{100, 2}, {101, 3}, {102, 2}, {103, 3}, {104, 1},
};
for (auto iter = map.begin(), end = map.end(); iter != end; ++iter) {
std::cout << "key : " << iter->first << " value : " << iter->second << '\n';
++(iter->second);
}
std::cout << "\n\n";
for (auto iter = map.begin(), end = map.end(); iter != end; ++iter) {
std::cout << "key : " << iter->first << " value : " << iter->second << '\n';
}
std::cout << "\n\n";
}
(See online)
But since you are using a range-based for loop you are accessing the values themselves, not an iterator to them. In that case, if you use auto you are getting a copy of the elements, and any changes you make are done the copies, not the elements themselves. If you instead use auto& you will get a reference instead, which is what you want:
#include <iostream>
#include <map>
int main() {
std::map<int, int> map {
{100, 2}, {101, 3}, {102, 2}, {103, 3}, {104, 1},
};
for (auto& [key, val] : map) {
std::cout << "key : " << key << " value : " << val << '\n';
++val;
}
std::cout << "\n\n";
for (auto& [key, val] : map) {
std::cout << "key : " << key << " value : " << val << '\n';
}
std::cout << "\n\n";
}
(See online)
Do note the use of structured bindings to simplify the code.

How can I print the elements of a vector as a ordered list using a range-based loop

Ex:
vector<string> myVec = {apple, banana, grape}
How can I print these elements as an ordered list using a range-based loop
Output:
1 apple
2 banana
3 grape
A variation of Jeffrey's answer, but without additional variable:
for (const auto& s : myVec)
{
std::cout << &s - &myVec[0] << " " << s << "\n";
}
This, of course, prints a "correct" 0-based index. Feel free to add 1 to it :)
Using boost ranges really simplifies things Live Demo
using namespace boost::adaptors;
std::vector<std::string> myVec = {"apple", "banana", "grape"};
for (const auto& element : myVec | indexed(1))
{
std::cout << element.index() << " " << element.value() << "\n";
}
Produces
1 apple
2 banana
3 grape
You are looking for
size_t position = 1;
for(const auto& s: myVec)
{
std::cout << position << " " << s << "\n";
position++;
}
as in
#include <iostream>
#include <string>
#include <vector>
using std::vector;
using std::string;
vector<string> myVec = {"apple", "banana", "grape"};
int main()
{
size_t position = 1;
for(const auto& s: myVec)
{
std::cout << position << " " << s << "\n";
position++;
}
}
With range-v3, you could write:
for (auto [i, val] : myVec | ranges::views::enumerate)
{
std::cout << i << ' ' << val << "\n";
}
Here's a demo.
This would be a good issue for the original for loop:
const size_t quantity = myVec.size();
for (unsigned int i = 0; i < quantity; ++i)
{
cout << (i + 1) << " " << myVec[i] << "\n";
}
Simple, effective. Don't knock the old stuff. :-)

How to read a map of <string,vector<pair<int, string>>>

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";
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:
random access (i.e, vec[index])
iterator (i.e, std::vector< std::pair<int, std::string>>::const_iterator itr;)
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;
}
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 ;)
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";
}
}
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";
}
}

C++: print out vector elements in a set container

I want to print out the vector element in a set container. I did the code as follows:
int main() {
vector<int> aa = {3, 2, 1, 1};
vector<int> bb = {5, 1, 7, 9};
set<vector<int>> myset; // setVector
myset.insert(aa);
myset.insert(bb);
for (auto elem : myset) {
cout << elem << ", ";
}
return 0;
}
However, this code can not print out the vector: (3, 2, 1, 1) and (5, 1, 7, 9).
you should also loop your vector elements inside myset.
for (auto const &elem : myset) { // loop set elements
for (auto const &v: elem) { // loop vector elements
std::cout << v << ", "; // print each vector element
}
std::cout << std::endl;
}
auto elem: myset here elem refers to the vectors.
to print out the contents of the vectors do this:
for (auto elem : myset)
{
for(auto x:elem) // elem is each vector
{
std::cout << x << " ";
}
std::cout << std::endl;
}
Here you iterate over the vectors in the inner for loop.
Also, you might want to use auto& in the loop if you are updating elements or to prevent copies since then you get a reference.
In order to print which you tried. You should overload << operator.
Also you may use like this.
for (auto elem : myset) {
cout << "(";
for(auto item:elem)
{
cout << item << ",";
}
cout << ")";
cout << endl;
}

printing a value of map which has two string as key and vector as value

I have a map which has two string as key and one vector as value
how can i print the value of map.
Below is my approach which is bad Can Someone help me thanks in advance
NOTE : i want to print by key not iterating on vector
int main()
{
vector<string>value;
std::map<std::pair<string,string> ,vector<string>> myMap;
string input1,input2,MyvectorValue;
for(int i=0;i<5;++i)
{
cin>>input1;
cin>>input2;
cin>>MyvectorValue;
myMap[std::make_pair(input1,input2)].push_back(MyvectorValue);
}
int j=0;
for( auto it = myMap.begin(); it != myMap.end(); ++it )
{
std::vector<std::string>& value = it->second.at(j++);
cout<<value // This is bad
//how can i print all map value ??
}
}
The value of the map is a vector, assuming you can use C++11, the following code would do what you need.
#include <string>
#include <iostream>
#include <map>
#include <utility>
#include <vector>
int main()
{
std::vector< std::string >value;
std::map< std::pair<std::string , std::string> , std::vector<std::string> > myMap;
std::string input1,input2,MyvectorValue;
for(int i=0;i<5;++i)
{
std::cin>>input1;
std::cin>>input2;
std::cin>>MyvectorValue;
myMap[std::make_pair(input1,input2)].push_back(MyvectorValue);
}
//If you have a particular key (string1, string2), and want to print the values for that specific key...
auto particularKey = std::make_pair("stringA", "stringB");
for(auto val : myMap[particularKey])
std::cout << val << " ";
std::cout << std::endl;
// If you want to iterate through all keys of your map
for(auto &elem : myMap)
{
std::cout << "for the pair with key (" << elem.first.first << "," << elem.first.second << "), the value is the following vector" << std::endl;
for(auto s : elem.second)
{
std::cout << s << " ";
}
std::cout << std::endl << std::endl;
}
return 0;
}
You can print the keys by accessing the pair and then using first and second to get the first and second member of the pair respectively.
You can also print the values, by accessing the vectors and iterating over them, printing every string separately.
for(auto& element : myMap)
{
std::cout << "Key: {" << element.first.first << ", " << element.first.second << "}\n";
std::cout << "Value is a vector with the following strings: \n";
for(auto& str: element.second)
std::cout << str << std::endl;
}
If you want to print by key not iterating on vector , then you may declare map as "std::map,string> myMap". Then, you can do following modification to your code as given below.
int main() {
vector<string>value;
std::map<std::pair<string,string>,string> myMap;
string input1,input2,MyvectorValue;
for(int i=0; i<5; ++i) {
cin>>input1;
cin>>input2;
cin>>MyvectorValue;
myMap[std::make_pair(input1,input2)]+=MyvectorValue;
myMap[std::make_pair(input1,input2)]+= " ";
}
for( auto it = myMap.begin(); it != myMap.end(); ++it ) {
std::string& value = it->second;
cout<<value<<endl;
}
}