How to update second value of map using iterator - c++

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.

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.

C++ map questions about syntax

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;
}
}

Finding most common element in a list (C++ STL)?

I have a program where I have to find the most common element in a list of integers. I do this with the program below, but the problem is, I suspect that the erase function messes up with the iterator incrementation in the countRepetition() function. My question is how can I fix the problem or if this is not the issue what is it?
Thanks in advance.
You have a couple issues. First, as you suspected, was the incorrect use of erase. When you erase an iterator it invalidates the iterator. Any use of the iterator afterwards is undefined behavior. Since erase returns the next valid iterator what you can do is restructure the loop like
for (START = l.begin(); START != l.end();) { // do not increment here
if (*START) {
counter++;
START = l.erase(START); // erase and get next
}
else
{
++START; // go to next
}
}
So now at least you loop through the list. Unfortunately you will still have an invalid iterator in main. You pass START from main to countRepetition and when that iterator is erased from the list you then have an invalid iterator. What you need to do is get a new begin iterator from the list each iteration since you are always erasing the first element. That would make your for loop look like
for (START = l.begin(); START != l.end(); START = l.begin()) {
m.push_back(countRepetition(START));
}
Another issue is you just check if the character is not 0. If you are counting repetitions you need to make sure you are checking that the iterator is the same character. I'll leave that for you to implement.
I would also like to point out there is an easier way to do all of this. A std::map lets you build a histogram very easily. Combine that with std::max_element and you could write your entire program as
int main()
{
std::map<char, int> histogram;
while ('0' != (number = getchar()))
++histogram[number]; // add to map, increment count of occurances
auto most_frequent = *std::max_element(histogram.begin(),
histogram.end(),
[](const auto& lhs, const auto& rhs) { return lhs.second < rhs.second; }).first;
std::cout << most_frequent;
return 0;
}
Your problem is that you use global variables everywhere.
The global START is changed in two loops, so you only access the first loop once, then it is changed again in the second function and you don't execute the first loop a second time.
Why do you use the global variables? You should not use them but use local variables.
This is probably what you are looking for:
#include <iostream>
#include <list>
#include <vector>
#include <map>
using namespace std;
list <char> l;
map<char, int> ans;
int main()
{
char c;
do{
c = getchar();
l.push_back(c);
}while(c != '0');
for(auto chr: l){
ans[chr]++;
}
char ch;
int mx = 0;
for(auto k: ans){
if(k.second > mx)
{
ch = k.first;
mx = k.second;
}
}
cout<<ch<<" : "<<mx;
}

incrementing the value in map using insert c++

I have the following problem - I want to count the occurrences of each word in a file. I'm using a map<string,Count> so the key is the string object representing the word, and the value being looked up is the object that keeps count of the strings so that :
class Count {
int i;
public:
Count() : i(0) {}
void operator++(int) { i++; } // Post-increment
int& val() { return i; }
};
The problem is that I want to use insert() instead of the operator[]. Here is the code.
typedef map<string, Count> WordMap;
typedef WordMap::iterator WMIter;
int main( ) {
ifstream in("D://C++ projects//ReadF.txt");
WordMap wordmap;
string word;
WMIter it;
while (in >> word){
// wordmap[word]++; // not that way
if((it= wordmap.find(word)) != wordmap.end()){ //if the word already exists
wordmap.insert(make_pair(word, (*it).second++); // how do I increment the value ?
}else{
...
}
for (WMIter w = wordmap.begin();
w != wordmap.end(); w++)
cout << (*w).first << ": "
<< (*w).second.val() << endl;
}
Could you refactor so as not to use find but simply attempt the insert?
Insert always returns a pair<iter*, bool>. The bool is 0 if it finds the key, and the iter* points to the existing pair. So we can take the pointer to the pair and increment the value:
// On successful insertion, we get a count of 1 for that word:
auto result_pair = wordmap.insert( { word, 1 } );
// Increment the count if the word is already there:
if (!result_pair.second)
result_pair.first->second++;
It was my first time posting. I'm learning C++ and welcome feedback on my idea.
The problem is that I want to use insert() instead of the operator[]
...why? std::map::insert cannot mutate existing values. operator[] is the right job for this.
If you really want to use insert (please don't), you first need to erase the existing value, if present:
if((it= wordmap.find(word)) != wordmap.end())
{
const auto curr = it->second; // current number of occurrences
wordmap.erase(word);
wordmap.insert(make_pair(word, curr + 1));
}

operation on 2 dimensional hash map C++

I am currently working on a coding question:
Given an array of strings, return all groups of strings that are anagrams.
For example, Given:
{asch, scah, bva, vba, soa}
return
{ {asch, scah}, {bva, vba}, {soa}}
To solve this question less than O(n^2) time, we should firstly sort each word, and group the sorted words in one set, if the sorted words are the same.
I wanted to use two-dimensional hashmap.
map<string, map<int,string>> container;
to use this two-dimensional hashmap, the first key is the sorted word, the second key is its index in the original sequence, and the value is the original word.
for(int i=0; i<sequence.size();i++)
{
string original_word = sequence[i];
string sorted_word = original_word;
sort(sorted_word.begin(),sorted_word.end());
container[sorted_word][i] = original_word;
}
After this loop, I believe all the anagrams which must have the same sorted_word, will be grouped into the first level of hashmap.
My question is, how should I write the code in order to get the set which has the same sorted_word?
Can I do
for( iterator itr = container.begin(); itr != container.end(); itr++)
{
auto grouped_words = itr.second(); // what is the data type of grouped_word here?
}
correct me if there is anything wrong. Thanks.
I think there's a mistake here:
vector<string, vector<int,string>> container; // ???
As in your question you speak about hash maps, I suppose that you meant:
unordered_map<string, unordered_map<int,string>> container;
In this case, you can use the result as follows:
for( auto itr = container.begin(); itr != container.end(); itr++)
{
auto &grouped_words = itr->second; // prefer a reference
cout << itr->first<<": ";
for (auto &x : grouped_words) {
cout << "\t" << x.first << ":"<< x.second<<endl;
}
}
Here a live demo.
Edit: grouped_words is (here) a reference to an unordered_map<int, string>