C++ map questions about syntax - c++

I am trying to learning more about maps in general:
i have never seen syntax like this before:
charMap[c]++;
i assume it is adding a char into as key? and incrementing the count as value? Would someone be able to provide where i can see this notation? I cant seem to find any information of this.
int firstUniqChar(string s) {
unordered_map<char, int> charMap;
for (char c : s)
charMap[c]++;
}
Also I was wondering, how come i receive an error when I try to insert into map but it works when i do map?
int firstUniqChar(string s) {
map<string,int> myMap;
for( int i=0; i<s.length(); i++){
auto it = myMap.insert({s[i],1});
if(!it.second){
it.first->second+=1;
}
}
auto itr = myMap.begin();
while(itr!=myMap.end()){
cout<<it->first;
it++;
}
}

unordered_map<char, int> charMap;
charMap[c]++;
std::map::operator[]:
Returns a reference to the value that is mapped to a key equivalent to key, performing an insertion if such key does not already exist.
So charMap[c] returns a reference to the mapped int that is increased with ++.
auto it = myMap.insert({s[i], 1});
There's no matching insert overload. Try using emplace:
auto it = myMap.emplace(s[i], 1);
Edit: I just noticed that you changed to a map with a string as key in your second part of the code and that you probably try to create a string from the char s[i] with length 1 when you do {s[i],1}, but that's the wrong way around. The count comes first, then the char - it also lacks the value part.
Using insert it could look like below. I'm using structured bindings to make it easier to see what's what.
map<string,int> myMap;
for(size_t i=0; i<s.length(); i++){
// create a string of length 1 mapped to the value 1
auto [it, inserted] = myMap.insert({{1, s[i]}, 1});
auto& [key, value] = *it;
if(inserted == false) {
++value;
}
}

Related

CoderPad C++ Hashmap did not work during job interview. Can you explain to me why?

So I had a job interview two days ago and they used coderPad.io for it, which is pretty common for job interviews. As a matter of fact, I have another job interview coming up that uses coderPad as well, so I really need to ask this question.
Essentially what happened was that my algorithm was written correctly. My interviewer told me so. However, the hash map was not working and we started debugging until the interviewer got tired and ended the interview right there. I then received a rejection email a day later. The interviewer did however narrow it down to the insert function on the hash map. We tried different ways of inserting and it still did now work.
I had to write an algorithm that needed for me to find the frequency for every integer element in a vector. However, when I had print the contents of the hash map, the frequency is always 1 for each element when it is not supposed to be 1 for each element. This had cost me the interview process to continue. I have recreated the algorithm on coderPad just now and the same issue is occurring. Here is the code:
#include <iostream>
#include <unordered_map>
#include <vector>
using namespace std;
// To execute C++, please define "int main()"
class hashMapTester {
public:
hashMapTester() {
}
unordered_map<int, int> collectMap(vector<int>& arr) {
unordered_map<int, int> map;
for (long unsigned int i = 0; i < arr.size(); i++) {
if (map.find(arr[i]) != map.end()) {
auto freq = map.find(arr[i])->second;
freq++;
map.insert(pair<int, int> (arr[i], freq));
} else {
map.insert(pair<int, int>(arr[i], 1));
}
}
return map;
}
void printMap(unordered_map<int, int> map, vector<int>& arr) {
for (const auto& iter : map) {
cout << iter.second << endl;
}
}
};
int main() {
vector<int> arr = {1, 2, 2, 3 , 4 , 4, 4};
hashMapTester hM;
unordered_map<int, int> map = hM.collectMap(arr);
hM.printMap(map, arr);
return 0;
}
Why is the frequency portion of the map always outputting 1 when it is not supposed to ? I am stuck on this and I really need to understand why. When I use this algorithm on LeetCode or on another compiler, it works, but not on CoderPad. Can anyone please help me out ? What do I need to do to make it work on CoderPad ?
Per https://en.cppreference.com/w/cpp/container/unordered_map/insert, the insert method "inserts element(s) into the container, if the container doesn't already contain an element with an equivalent key."
The call to insert in the following section won't actually change the contents of the unordered_map.
if (map.find(arr[i]) != map.end()) {
auto freq = map.find(arr[i])->second;
freq++;
map.insert(pair<int, int> (arr[i], freq)); // <<-- here
}
Option 1: Make freq a reference
if (map.find(arr[i]) != map.end()) {
auto& freq = map.find(arr[i])->second;
freq++;
}
Option 2: Simplify the algorithm,
unordered_map<int, int> collectMap(const vector<int>& arr) {
unordered_map<int, int> map;
for (int val : arr) {
++map[val];
}
return map;
}
To quote cppreference:
Inserts element(s) into the container, if the container doesn't already contain an element with an equivalent key.
You should probably use operator[] instead.

How to update second value of map using iterator

I have a function in which it checks for the characters and number of times it is repeated in a string.
It is stored as (for example)string is "hello" [h]=>1 [e]=>1 [l]=>2 [o]=1
Whenever a letter occurs more than once I need to update it.
I tried using
it->second = it->second+1;
But it doesn't works
How can I do that?
Full code is
int fn(string a) {
map<char,int> mymap;
for(int i=0;i<a.size();i++)
{
std::map<char, int>::iterator it = mymap.find(i);
if(it!=mymap.end())
{
//say i need to update occurrence from 1 to 2 or 2 to 3...
it->second = it->second+1;//(how can i do that)
}
else
mymap.insert(pair<char,int>(a[i],1));
}
std::map<char,int>::iterator i;
for(i=mymap.begin();i!=mymap.end();i++)
{
cout<<i->first<<i->second;
}
}
You don't need all that code. You can just say
for (auto c : a) mymap[c]++;
This works because map's operator[] inserts a zero initialized element when one doesn't exist for a given key.

Return a map in C++ to use as a table in lua

I want to be able to return a table of values, not userdata, stored data in a map, like integers, strings etc, in lua using C++. How would I go about doing this?
Sorry I don't have a complete example to give.
This is the map.
std::map<uint16_t, std::map<std::string, uint32_t>> myMap;
void getMyMap(uint16_t i, std::string a, uint32_t& v) {
v = myMap[i][a];
}
I know this isn't a template, but hypothetically if it was.
Edit :
I figured it out on my own. I won't give you exactly what I was working on but I will provide a generic detailed answer using the above code in mind.
std::map<uint16_t, std::map<std::string, uint32_t>> myMap;
void getMyMap(uint16_t i, std::string a, uint32_t& v) {
v = myMap[i][a];
}
std::map<std::string, size_t> getMapData(uint16_t i){
return myMap[i];
}
int LuaReturnTableOfMap(lua_State *L)
{
uint16_t data = 2;// used just for this example
// get the data stored
std::map<std::string, size_t> m = getMapData(data);
// get the size of the map
size_t x = m.size();
// create the table which we will be returning with x amount of elements
lua_createtable(L, 0, x);
// populate the table with values which we want to return
for(auto const &it : m){
std::string str = it.first;
const char* field = str.c_str();
lua_pushnumber(L, it.second);
lua_setField(L, -2, field);
}
// tell lua we are returning 1 value (which is the table)
return 1;
}
I cannot recommend Sol2 (https://github.com/ThePhD/sol2) enough for C++/Lua.
In c++ you can assigned nested maps and it is smart enough to created nested lua tables for you:
std::map<int, std::map<std::string, int>> nestedmap;
std::map<std::string, int> innermap;
innermap["frank"] = 15;
nestedmap[2] = innermap;
sol::state lua;
lua.set("mymap", nestedmap);
Then in your lua script, you can access it just like a table:
print("Testing nested map: " .. mymap[2]["frank"]) -- prints 15

checking 'deepest' element in map

I have a map<int, map<int, int>>.
The first key stands for node, the second key stands for an attribute, and the 'deepest' element represents a particular value.
I need to check that element, but doing the following unnecessary adds keys to my map:
map<int, map<int, int>> test;
if (test[4][3] > 5)
{
//do something
}
The alternative as I think of it is
map<int, map<int, int>> test;
if (test.find(4) != test.end())
{
if (test[4].find(3) != test[4].end())
{
if (test[4][3] > 5)
{
//do something
}
}
}
Is there a better way to do this? I don't know if there exists the key [4][3] in the map, and I don't want to unnecessarily add it. Thanks!
This should work - first you search in the first map and saves the returned iterator, then if that iterator is valid you search the map that he points to and saves the result in another iterator, and if he's valid that means that the objects you seek exists and you just check the value of it:
map<int, map<int, int>> test;
map<int, map<int, int>>::iterator it1;
map<int, int>::iterator it2;
if ((it1 = test.find(4)) != test.end())
{
if ((it2 = it1->second.find(3)) != it1->second.end())
{
if (it2->second > 5)
{
//do something
}
}
}
return 0;
Not fundamentally different from Tomer Arazy's suggestion, but making use of C++11's decltype to get rid of repeated type declarations (correcting which can be tedious when you modify the data type of the map):
#include <map>
#include <iostream>
int main()
{
using std::map;
map<int, map<int, int>> test;
test[4][3] = 6;
decltype(test.begin()) outer;
decltype(test.begin()->second.begin()) inner;
if (((outer = test.find(4)) != test.end())
&& ((inner = outer->second.find(3)) != outer->second.end())
&& (inner->second > 5))
std::cout << "Found!" << std::endl;
return 0;
}
(Note that the argument of decltype() isn't evaluated, so this works even if the map is empty.)
This will obviously only work with C++11.
Another thing to mention in the context of C++11 is that std::map has now an at() function similar to std::vector. It returns the value for a given key, and throws an exception if the key doesn't exist. This only a useful idea if you consider the non-existence of the key as an error condition. But if so, you could use
if (test.at(4).at(3) > 5)
std::cout << "Found!" << std::endl;
And then possibly catch the std::out_of_range exception somewhere.
I think this might make it a bit easier to see what's going on:
map<int, map<int, int>> test;
map<int, map<int, int>>::iterator outer = test.find(4);
if (outer != test.end())
{
map<int, int>::iterator inner = outer->second.find(3);
if (inner != outer->second.end())
{
if (inner->second > 5)
{
//do something
}
}
}
return 0;

Copying C++ Map into key and value vectors

I have a map and I want the first column i.e (*it).first to be pushed back into a vector then (*it)->second to be pushed back into another vector
Is this the best way to do it?
std::vector<std::string>test;
for ( it=mymap.begin() ; it != mymap.end(); it++ )
{
test.push_back((*it).first);
}
My other question is if i have a loop i.e
how would I insert all the integers i into (*it).first?
for(int i = 0; i < 10; i++)
{
// 1 - 10 will go in (*it).first
}
I want to have some integers in (*it).first and have associated values in (*it).second;
Use std::transform.
First define two functions key and value which take the pair of strings and return the first or second value, respectively.
#include <map>
#include <vector>
#include <algorithm>
#include <iostream>
#include <iterator>
const std::string& key(const std::pair<std::string, std::string>& keyValue)
{
return keyValue.first;
}
const std::string& value(const std::pair<std::string, std::string>& keyValue)
{
return keyValue.second;
}
Then use std::transform from <algorithm> with the functions to transform the map into either a vector of keys or a vector of values.
int main()
{
using namespace std; // be explicit normally, trying to be brief here
map<string, string> contacts;
contacts["alice"] = "555-2701";
contacts["bob"] = "555-2702";
vector<string> keys(contacts.size());
vector<string> values(contacts.size());
transform(contacts.begin(), contacts.end(), keys.begin(), key);
transform(contacts.begin(), contacts.end(), values.begin(), value);
cout << "Keys:\n";
copy(keys.begin(), keys.end(), ostream_iterator<string>(cout, "\n"));
cout << "\n";
cout << "Values:\n";
copy(values.begin(), values.end(), ostream_iterator<string>(cout, "\n"));
return 0;
}
Output:
Keys:
alice
bob
Values:
555-2701
555-2702
Your first question, "how can I push the first column of my map into one vector and the 2nd column into another" is solved thus:
std::map<std::string, std::string> mymap;
std::vector<std::string> keys;
std::vector<std::string> values;
for ( std::map<std::string,std::string>::iterator it=mymap.begin() ; it != mymap.end(); ++it )
{
keys.push_back(it->first);
values.push_back(it->second);
}
Your second question, "how would insert all the integers i into (*it).first ?" is solved thus:
std::map<int, int> mymap2;
for(int i = 0; i < 10; i++)
{
// Insert default value into map
// This sets '(*it).first' to 'i' and
// '(*it).second' to a default value (in
// this case, 0).
mymap2[i];
}
or
std::map<int, int> mymap3;
for(int i = 0; i < 10; i++)
{
// Insert specified value into map
// this sets '(*it).first' to 'i', and
// '(*it).second' to the value returned from the function.
maymap3[i] = ChooseSpecificValue(i);
}
Well, it can be done with a simple loop:
for (auto const& p: mymap) {
vec1.push_back(p.first);
vec2.push_back(p.second);
}
Or using the std::transform algorithm, though it's quite verbose here:
std::transform(mymap.begin(), mymap.end(), std::back_inserter(vec1),
[](MyMap::const_reference p) { return p.first; });
Assuming you've declared your map as string key and value (ie map<string, string> mymap; then it would be like below, also assuming you've declare 'it' variable as map<string, string>::iterator it, etc:
std::vector<std::string> test;
std::vector<std::string> second;
std::map<string, string>::iterator it;
for ( it=mymap.begin() ; it != mymap.end(); it++ )
{
test.push_back((*it).first);
second.push_back((*it).second);
}
Not sure about your next question.
The first part of your question:
std::vector<std::string> test;
std::vector<std::string> test2; // assuming map is from string to string
for (it = mymap.begin(); it != mymap.end(); ++it)
{
test.push_back(it->first); // push first in one vector
test2.push_back(it->second); // push second in another vector
}
So, yes a simple for can do what you want.
The second part of your question:
Since you are updating the key of the map, you would need to remove it from the map and insert the changed one. So:
std::string first, second;
first = it->first;
second = it->second;
mymap.erase(it); // be careful with invalidating iterator
// change first
mymap[first] = second;
To change first by adding all integers i to it, that would really depend on the type of first. For example with a string, you may mean something like this:
ostringstream sout;
for (int i = 0; i < 10; ++i)
sout << (i?" ":"") << i;
first = sout.str();
Or if first is for example a set, you may mean something like this:
for (int i = 0; i < 10; ++i)
first.insert(i);
and my other question is if i have a loop i.e how would insert all the
integers i into (*it).first?
In the case of a std::map, you can't modify the iterator returned like that ... the key member (i.e., the first) in the std::map key/value pair data-structure is intentionally designated as a constant value, and is initialized to its constant value at the beginning of the key/value pair's lifetime in the std::map data-structure. If the keys weren't constant, you would end up creating havoc when you change the key, since the nodes in a std::map are suppose to be sorted by the keys. The second member of the key/value pair data-structure is the member that can be changed.
So if you want to insert a set of key/value pairs in a map, you could simply do the following:
std::map<int, int> mymap;
int some_other_value = 100;
for (int i=0; i < 10; i++)
{
mymap[i] = some_other_value++;
}
it here will be an iterator which will point to one of the position in map and at max have one first and second value for one iterator . At max you can have multiple key or same key holding same/different values depending on key/value combination.
As far as pushing the value in the vector for a key in map is concern you can do it in the same way you are pushing the key
std::vector<std::string>test;
std::vector<std::string>test2;
for ( it=mymap.begin() ; it != mymap.end(); it++ )
{
test.push_back((*it).first);
test2.push_back((*it).second);
}
Neways yours question is very unclear .
Just in case you want to deal with different data types in your map I would template a generic copy function:
template <class A, class B>
void mycopy(std::map<A, B>&m, std::list<A>& keys, std::list<B>& values) {
typename std::map<A, B>::iterator it;
for (it = m.begin(); it != m.end(); ++it) {
keys.push_back( (*it).first );
values.push_back( (*it).second );
}
}
Mixing it up:
std::map<int, std::string> mymap;
std::list<int> keys;
std::list<std::string> values;
mymap[1] = "string1";
mymap[2] = "string2";
mycopy(mymap, keys, values);
std::map<std::string, int> mymap1;
std::list<std::string> keys1;
std::list<int> values1;
mymap1["string1"] = 1;
mymap1["string2"] = 2;
mycopy(mymap1, keys1, values1);
Edit: yes __copy isnt the best definition. Thanks