Print C++ Map by iteration - c++

Is there an easier way to go about this or is there something I'm doing horribly wrong? I think that the core of my problem is in the code,
vector<int> &v = miss_words[*i];
but maybe I'm just getting the whole concept wrong. Any suggestions?
CODE:
void print_map(map<string, vector<int> > miss_words) // Prints out dictionary set
{
map<string, vector<int> >::iterator it = miss_words.begin(); // Creates an iterator
while(it != miss_words.end()) // While hasn't reached the end
{
vector<int> &v = miss_words[*it]; // Accesses Vector in map
for(unsigned int g = 0; g <= v.size(); g++)
{
cout<<v.at(g)<<": ";
cout<<v.at(g)<<" "<<endl; // Print out data at i
}
it++; // Increment iterator
}
}
The compiler puts says that there is "no match for 'operator[]' in miss_words.

You want to say vector<int> &v = it->second;
The iterator's value type is the value type of the map, i.e. pair<string, vector<int>>.
In fact, in modern C++ you could write this more simply, and less error-prone, like so:
for (auto const & p : miss_words)
{
for (auto const & x : p.second)
{
cout << x << ": " << x << " \n";
}
}
That way, you don't even need to worry about the size of your vector.

Related

C++ Loop through first K elements of unordered_map

I have an unordered_map that stores counts of integers. I want to loop through the map, but instead of fetching all the entries, I only wish to get the first K.It is guaranteed that map has more than K entries.
I'm running into issues when I do the following:
unordered_map<int, int> u_map;
// Logic to populate the map
for(auto it=u_map.begin(); it!=u_map.begin()+2; it++)
cout<<it->first<<" "<<it->second<<endl;
The expression u_map.begin()+2 is causing the issue.
So is it possible to get only the first K entries of a map using for_each loop in C++?
If you can use C++20, then views::take would be a choice.
#include <unordered_map>
#include <ranges>
#include <iostream>
int main() {
std::unordered_map<int, int> u_map;
for (auto [key, value] : u_map | std::views::take(2))
std::cout << key << " " << value << "\n";
}
Alternative for pre-C++20, using std::next:
std::unordered_map<int, int> u_map;
auto end = std::next(u_map.begin(), 2);
for (auto it = u_map.begin(); it != end; ++it)
std::cout << it->first << " " << it->second << "\n";
I only wish to get the first K
Note from std::unordered_map documentation
an unordered_map object makes no guarantees on which specific element is considered its first element.
This essentially means that there is no guarantee that you will iterate over the elements in the inserted order.
For iterating over the elements of the map you can use:
int count = 0;
for (auto& it: u_map) {
/* some code here like you can keep a count variable that will check if it
reaches the number K and then break the loop. But remember that it is
**not** guaranteed that the elements you will get will be in inserted order.*/
if(count < K)
{
cout<<it.first<<" "<<it.second<<endl;
}
else
{
break;
}
++count;
}
Working example
#include <iostream>
#include <unordered_map>
using namespace std;
int main()
{
std::unordered_map<std::string, std::string> u_map = {
{"RED","#FF0000"},
{"GREEN","#00FF00"},
{"BLUE","#0000FF"},{"PURPLE","#0F00FF"},{"WHITE","#0000RF"},{"ORANGE","#F000FF"}
};
int K = 3;
int count = 0;
for (auto& it: u_map)
{
if(count < K)
{
cout<<it.first<<" "<<it.second<<endl;
}
else
{
break;
}
++count;
}
return 0;
}

Ordering in unordered_map in C++

So I have an array as :
arr[] = {5, 2,4,2,3,5,1};
How can I insert them in this order with the number of times they occur in unordered_map?
#include<bits/stdc++.h>
using namespace std;
void three_freq(int arr[], int n){
unordered_map<int, int> m;
for(int i=0;i<n;i++){
m[arr[i]]++;
}
for(auto itr = m.begin(); itr != m.end(); itr++){
cout<<itr->first<<":"<<itr->second<<"\n";
}
}
int main(){
int arr[] = {5, 2,4,2,3,5,1};
int n = sizeof(arr)/ sizeof(arr[0]);
three_freq(arr, n);
return 0;
}
Using the code above I am getting output as :
1:1
3:1
4:1
5:2
2:2
But I want the output to be in same order as the element occur in array.
Example:
5:2
2:2
4:1
3:1
1:1
If you don't care about efficiency (that much), then you can just change the for loop which is printing the output.
for(int i=0; m.size(); i++) {
auto it = m.find(arr[i]);
if (it != m.end()) {
cout<<arr[i]<<":"<<it->second<<"\n";
m.erase(it);
}
}
The quite efficient way is traversing the original array and resetting the counters after print.
for (int i = 0; i < n; ++i) {
if (m[a[i]]) != 0) {
std::cout <<arr[i] << ":" << m[a[i]] << std::endl;
m[a[i]] = 0;
}
}
You need unordered_map to do the counting efficiently, so keep that.
When printing out according to the order in another container, it makes sense to simply iterate over that other container for your output loop.
(Note that this is a completely separate operation, so it could have been a different function.)
// loop over the original array (recommend std::vector)
// exit early if done (stole from fadedreamz)
for (int index = 0; !m.empty(); ++index) {
int number = arr[index];
// check to see if we need to print this number
// use contains if you have c++20
if (m.count(number)) {
std::cout << number << ":" << m[number] << std::endl;
m.erase(number); // print only once by deleting the entry
}
}

copy a vector<string> elements to other other vector<string>* (1 passing as pointer)

void check_and_fix_problems(vector<string>* fileVec, int index) {
vector<string> q = { "something", "else", "here" };
q.insert(q.end(), fileVec->begin() + index + 2, fileVec->end()); //add at the end of q vector the fileVec vector
for (int f = 0; f < q.size(); f++) {//here is the problem/s
std::copy(q.at(f).begin(), q.at(f).end(), fileVec->at(f)); //copy q vector to fileVec
//fileVec->at(f) = q.at(f);
}
}
i have problem with this code, when i call it i get runtime error for the fileVec vector out of range (i guess because the q vector has more elements than the fileVec so some indexes are out of range) but how i can increase the vector size of the vector via their pointer?
and also is here important to use std::copy or i can simple do the same with fileVec->at(f) = q.at(f);?
(because as i know, when this function return everything in the function will deleted and the result will be all elements in fileVec showing at nullptr).
So here I tried fixing your code, though I still did not know what exactly you were doing. I assumed you need to insert another vector elements at a given index in another vector. Once you will tell the exact requirement, it can be modified accordingly :
void check_and_fix_problems(std::vector<string> &fileVec, int index) {
std::vector<string> q = { "something", "else", "here" };
q.insert(q.end(), fileVec.begin() + index + 2, fileVec.end()); //add at the end of q vector the fileVec vector
//for debugging purpose
std::cout << "q in function contains:";
for (std::vector<string>::iterator it = q.begin() ; it < q.end(); it++)
std::cout << ' ' << *it;
std::cout << '\n';
//vector<string>::iterator itr;
// for (itr = q.begin(); itr != q.end(); itr++) {//here is the problem/s
// fileVec.insert(fileVec.begin() + index,*itr); //copy q vector to fileVec
// //fileVec->at(f) = q.at(f);
// }
fileVec.insert(fileVec.begin() + index, q.begin(),q.end());
}
int main ()
{
std::vector<string> a = {"xyz","abc","says","hello"};
check_and_fix_problems(a, 1);
std::cout << "a contains:";
for (std::vector<string>::iterator it = a.begin() ; it < a.end(); it++)
std::cout << ' ' << *it;
std::cout << '\n';
return 0;
}
This gave the following output :
q in function contains: something else here hello
a contains: xyz something else here hello abc says hello

looping over set inside map in cpp

I am getting error in for loop ,compiler saying that 's' must have a pointer type (in s->second.begin()).I just want to iterate over set below.
vector<vector<int>> verticalTraversal(TreeNode* root) {
map<int, map<int, set<int>>> mep;
solve(root, 0, 0, mep);
vector<vector<int>> result;
for (auto p : mep) {
vector<int> temp;
map<int,set<int>> s = p.second;
for (auto ity = s->second.begin(); ity != s->second.end(); ity++) {
//getting error here in s->second.begin()
}
//reverse(temp.begin(), temp.end());
result.push_back(temp);
}
return result;
}
So here's some code that iterates through each set (and prints out all the integers).
vector<vector<int>> verticalTraversal() {
map<int, map<int, set<int>>> mep;
solve(root, 0, 0, mep);
vector<vector<int>> result;
for (map<int, map<int, set<int>>>::iterator i = mep.begin(); i != mep.end(); ++i) {
for (map<int, set<int>>::iterator j = i->second.begin(); j != i->second.end(); ++j) {
for (set<int>::iterator k = j->second.begin(); k != j->second.end(); ++k) {
cout << *k << '\n';
}
}
}
return result;
}
First thing you should notice is that there are three loops not two, since you have a set inside a map inside a map you have three levels to iterate though (not two as in your code).
Second thing is I removed all auto and all range based loops and been completely explicit about the types involved. Hopefully that makes the code easier to understand.
Once you've understood it you can put the auto back in if you like, or even replace the loops with range based loops.
The best thing to do is to write a small program, and then get an idea/experiment with the smaller program to understand the basic concepts.
Here is an example:
#include <map>
#include <set>
#include <iostream>
int main()
{
std::map<int, std::map<int, std::set<int>>> mep;
mep.insert({0, {{0, {0,1,2,3}}}}); // populate the map
mep.insert({1, {{1, {1,2,3,4,5}}}}); // populate the map
// traverse each set in the mep map
for (auto p : mep)
{
std::map<int, std::set<int>> s = p.second;
for (auto ity = s.begin(); ity != s.end(); ity++)
{
std::set<int>& theSet = ity->second;
for (auto& setV : theSet )
std::cout << setV << " ";
std::cout << "\n";
}
}
}
Output:
0 1 2 3
1 2 3 4 5
Also note that you really should be using references to the data within the map instead of copying them by value. Things like this:
for (auto p : mep)
and
std::map<int, std::set<int>> s = p.second;
incurs a copy. Rather, you should do this:
for (auto& p : mep)
...
std::map<int, std::set<int>>& s = p.second;

How to use std::map to retrive a std::vector<int> in c++?

What I'm trying to do is to somehow replicate in c++ the structure and functionality of a Perl Hash. For those not familiar with Perl, in such language a key can be used to point not only to a variable but other more complicated structures like arrays or vector or even other hashes. What I have tried so far is to create a vector of size 10 which is going to be my mapped_type
size_t size = 10;
std::vector<int> v1(size);
... Code that fills the v1...
and then create the map with v1 and fill it with values.
std::map<unsigned int, v1> x;
std::map<unsigned int,std::vector<int>>::iterator p=x.find(key);
if(p==m.end()) m[key]=v1;
Later, I plan to loop through all the keys and retrieve the vectors associated with those keys
for (std::map<unsigned int, std::vector<int>>::iterator p=x.begin(); p!=x.end(); ++p) {
...Do something with the p...
}
but of course these two last piece of code does not work at all.
I have successfully created other iterators like
std::map<unsigned int, unsigned int> x;
std::map<unsigned int, unsigned int>::iterator p=x.find(key);
if(p==m.end()) m[key]=1;
for (std::map<unsigned int, unsigned int>::iterator p=x.begin(); p!=x.end(); ++p) {
...Do something with the p...
}
but the mapped type is just a variable containing a single number or character. I want to be able to call and work with a complete vector using map (or any other C++ functionality). Is there a way to do this?
The problem is with the line:
std::map<unsigned int, v1> x;
You can't use v1 as the mapped type as v1 is not a type, it is an instance of a type. You can either write the type explicitly:
std::map<unsigned int, std::vector<int>> x;
Or use decltype:
std::map<unsigned int, decltype(v1)> x;
Also, if you want a hash map then you should use std::unordered_map rather than std::map, which is actually a red-black tree
With C++11 you might do something like this:
#include <iostream>
#include <map>
#include <vector>
int main() {
// type helpers
using MyVec = std::vector<int>;
using MyMap = std::map<unsigned int, MyVec>;
// create v1
MyVec v1 { 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 };
// Or MyVec v1; v1.resize(10);
// create the map
MyMap x;
unsigned int key = 123;
auto it = x.find(key);
if (it == x.end())
x[key] = v1; // causes a COPY of the entire vector
for (const auto& idx: x) {
// idx.first is the key
// idx.second is the vector
std::cout << idx.first << ": ";
for (auto val: idx.second) {
// ^ no &, makes copies of values but they're ints so it's ok.
std::cout << val << " ";
}
std::cout << "\n";
}
}
Live demo: http://ideone.com/1r13zB
This give some clues as to how to iterate through a map. Using p->second gives you complete access to the int vector, and p->first gives you complete access to the map's key.
std::map<unsigned int, v1> x; // v1 -> typo?
std::map<unsigned int, std::vector<int> > x; // does this work?
I'm not sure if you're copying your code directly or providing pseudo code, but when you nest template arguments you have to insert a space into the final right angle brackets since >> is a C++ operator. I would imagine you would have found this out by getting a build error though.
I often use similar (nested) structures and i know this approach work, so consider the following, if this answers your question.
Your example is a map with int keys and vector values.
std::map< unsigned int, vector<int> > myMap;
// fill some vectors and put them in the myMap
for (int i = 0 ; i < 10 ; i++){
vector<int> myValueHolder;
for (int j = 0 ; j < 10 ; j++){
myValueHolder.push_back(10*i + j);
}
myMap[i] = myValueHolder;
}
// vectors are filled and pushed into the map with int keys
// retrieve vectors
for (std::map<unsigned int, vector<int> >::iterator iter = myMap.begin() ; iter != myMap.end() ; iter++ ){
unsigned int currentKey = iter->first; // first gets the key in the
vector<int> currentValue = iter->second; // second get the value
cout << "key is: " << currentKey << endl << "values are:" << endl;;
for (unsigned i = 0 ; i < currentValue.size() ; i++){ cout << currentValue.at(i) << endl; }
}
// or using any of the keys
vector<int> someRandomVectorFromTheMap = myMap[5];
for (unsigned i = 0 ; i < someRandomVectorFromTheMap.size() ; i++){ cout << someRandomVectorFromTheMap.at(i) << endl; }
I tested this and works as expected, hope answers what you ask. And i compiled it with this flag
COMPILE_AS_Cpp0X = $(-std=c++14) in case you wonder if it's 14 compatible
EDIT: I forgot to mention that what you wrote suggests you are not very familiar with the maps and their iterator methods first and second. This methods are very useful when iterating over map elements. Also usage of .find()
vector<int> someVectorTofind = myMap.find(8)
OR if you want to check if such key exists
vector<int> holder;
if (myMap.find(15) != myMap.end()) { holder = myMap.at(15)};
Check more map and vector examples is my suggestion
If you try to define the map with type of v1, you need decltype()
#include <string>
#include <vector>
#include <map>
int main( void )
{
size_t size = 10;
std::vector<int> v1(size);
std::map<unsigned int, decltype(v1) > x;
return 0;
}
Now I'm unsure what you're trying to do with a map<unsigned int, vector int> but the most likely case is that you really want a multimap<unsigned int, int>. With this you could do something like:
while(it != x.cend()) {
auto end = x.upper_bound(it->first);
cout << it->first << "\n\t";
for_each(it, end, [](const auto& i){ cout << i.second << '\t'; });
cout << endl;
it = end;
}
Live Example
Which would print your key on one line and an indented tab delineated list of the values associated with the key. There are lots of other clever things you can do with multimap, you can read about the functionality here: http://en.cppreference.com/w/cpp/container/multimap
One thing about your question, you allude to Perl's weak typing. Where you can assign an int to a variable and then turn around and assign a number to it. That's not possible in C++, because it's strongly typed: https://en.wikipedia.org/wiki/Strong_and_weak_typing
What you can do, and what I do in my example, is to assign a char's value to an the int value of the multimap. This assignment will cast the integral value of the character to an int. If you want the character back all you'll need to do is static_cast it back to a char.