Modifying unordered_map in loop - c++

This is a pretty simple unordered map question, but I haven't found an explicit answer. If I have some unordered map, say
unordered_map<int, double> aggregateCollisions
and I want to multiply the value associated with every key by some constant double, say C, does the following do this?
for(auto pair : aggregateCollisions)
{
pair.second *= C;
}

Related

Push_back into map<int,vector<char>>*

c++
map<int, vector>* maxcounts;
When I have a pointer to map maxcount how do I write this next statement correctly?
maxcounts[-m.second]->push_back(m.first);
without referencing a pointer I write
maxcounts[-m.second].push_back(m.first);
map<int, vector<char>> maxcounts;
for (pair<char, int> m : counts) {
if (maxcounts.count(-m.second))
maxcounts[-m.second].push_back(m.first);
else
maxcounts.insert({ -m.second, {m.first} });
}
To figure out how to use a pointer to the map, first rewrite your loop this way:
std::map<char, int> counts;
//...
std::map<int, std::vector<char>> maxcounts;
for (std::pair<char, int> m : counts)
maxcounts.insert({-m.second, std::vector<char>()}).first->second.push_back(m.first);
Note that the return value for std::map::insert is a std::pair, where the first of the pair is an iterator to the existing item if the item already is in the map, or the iterator to the newly inserted item. Thus you can perform the test and insert in one line without need for an if statement.
The push_back will occur, regardless of whether the item inserted in the map is new or if the item existed. Note that for a new entry, the std::vector being inserted starts as empty.
Given this, the pointer to the map version is very simple:
std::map<char, int> counts;
//...
map<int, vector<char>>* maxcounts;
//
for (pair<char, int> m : counts)
maxcounts->insert({-m.second, std::vector<char>()}).first->second.push_back(m.first);
Now, why you need a pointer to a map in the first place is another issue, but to answer your question, the above should work.
I would likely write something like:
std::map<int, std::vector<int>>* maxcounts = ...;
for (std::pair<char, int> m : counts)
(*maxcounts)[-m.second].push_back(m.first);

how to traverse in a unordered_map of unordered_map of unordered_map in c++

I wanted to traverse inside a data structure - unordered_map<int, unordered_map<int, unordered_map<int, int>>> myMap. To further specify I want to get the data elements like ->
myMap[someVal1][someVal2]
{all second elements of this unordered map}
I am aware of the fact that the same could by done by a 3d array however using a 3d array would not be efficient as the data range is huge and the program would end up using far more space than required.I tried using some iterators like unordered_map<int, unordered_map<int, unordered_map<int, int>>>::iterator i, and several other such iterators however it always ends up in some error or the other. Could someone help me in understanding how this map can be traversed ? Thanks in advance!
You could traverse the map with a foreach loop (it needs C++11, I think that won't be a problem), if you don't want to use iterators.
myMap mapMapMap;
for(auto& mapMap : mapMapMap){
for(auto& map : mapMap.second){
for(auto& key_value : map.second){
int key = key_value.first;
int value = key_value.second;
// ....
}
}
}
Also, if you didn't want to iterate all the map, but only the values of the third level, given the two first, then this should make it:
int k1, k2;
for(auto& key_value : myMap.at(k1).at(k2)){
//...
}

c++ cannot find element is unordered_set with the same hash

I have custom hash function for unordered_set of vectors< int >:
struct VectorHash {
int operator()(const vector<int> &V) const {
int hsh=V[0] + V[1];
return hash<int>()(hsh);
}};
And for two such vectors I have the same hash equal 3:
vector<int> v1{2,1};
vector<int> v2{1,2};
But when I try to insert first vector v1 in unordered_set, and then check if I have the same vector by hash as v2 in my unordered_set I get false:
std::unordered_set<std::vector<int>, VectorHash> mySet;
mySet.insert(v1);
if(mySet.find(v2) == mySet.end())
cout << "didn't find" << endl;
Output: "didn't find"
I assume that if two elements in unordered_set have the same hash then if I have v1 in my unordered_set, find method should return true, when I try to find v2. But it is not the case.
Could anyone explain me what is wrong in my reasoning?
Hash isn't everything, what you're seeing here, is a collision.
Both std::vector<int> have the same hash value here, but after hash is calculated, std::unordered_map will actually actually check for equality of elements using operator== to check for equality of elements, which fails in this case, and fails to find the element.
Collisions are a normal thing in HashMaps, not much you can do here without providing custom operator==.
I assume that if two elements in unordered_set have the same hash then if I have v1 in my unordered_set, find method should return true, when I try to find v2.
That assumption is incorrect, same hash doesn't mean objects are equal.
unordered_map uses the equality predicate to determine key equality (by default std::equal_to).
If you happen to want unique identifiers but not automatically compare values, you could use an (unordered_)map<int, vector<int>> and use that VectorHash function to generate the int key:
unordered_map<int, vector<int>> map;
int key=V[0] + V[1]
map[key] = V;
you need to provide a comparator to the unordered_set as well if you want the two elements to match, you can do something along the lines of this:
struct VectorComparator {
bool operator()(const std::vector<int> & obj1, const std::vector<int> & obj2) const
{
if ((obj1[0] + obj1[1]) == (obj2[0] + obj2[1]))
return true;
return false;
}
};
and create your unordered_set like this
std::unordered_set<std::vector<int>, VectorHash, VectorComparator> mySet;
Then you should get the result you are expecting

Loss of data while ordering an unordered_map c++

I have a unordered_map<string, int> freq and I order it transforming it into a
map<int,string> freq2. I use the next function in order to do that:
map<int, string> order(unordered_map<string, int> x) {
map <int, string> map;
for (auto it = x.begin(); it != x.end(); ++it) {
map.emplace(it->second, it->first);
}
return map;
}
the size of the unordered_mapis 2355831 and the returned map is 505, so as you see the loss of data is quite big and i have no idea why....
Any idea why this happens?
Thanks.
EDIT:
Thanks to all, you are all right, I have a lot of int with same value, that´s why i loose the data( really stupid from my part to not see it before)
Most likely this is because there are duplicates among the int values. Try replacing map<int, string> with multimap<int, string>.
The code itself looks fine. However, since you are mapping from string keys to integers, it might be very well that you have multiple keys with the same value.
From the documentation of emplace:
The insertion only takes place if no other element in the container has a key equivalent to the one being emplaced (keys in a map container are unique).
So if a lot of your entries in the first map have the same value (which is the key in the second map), then your dataset will decrease by a lot.
If you need to preserve those elements, then std::map is not the right container.

Elegant and efficient algorithm for increasing values of a "vector<pair>"

I need to find an element in a vector<pair<int, float>> and increase the second value.
I tried an approach.
template <typename K, typename V>
struct match_first {
const K _k; match_first(const K& k) : _k(k) {}
bool operator()(const pair<K, V>& el) const {
return _k == el.first;
}
};
Eg to use.:
vector< pair<int, float> > vec;
vec.push_back(make_pair(2, 3.0));
vec.push_back(make_pair(3, 5.0));
vec.push_back(make_pair(1, 1.0));
vector< pair<int, float> >::iterator it = find_if(vec.begin(), vec.end(), match_first<int, float>(3));
if (it != vec.end()) {
it->second += 9;
}
There is a more efficient way of accomplishing this task?
A map seems more natural:
#include <map>
int main()
{
std::map<int, float> m;
m.insert(std::make_pair(2, 3.0));
m.insert(std::make_pair(3, 5.0));
m.insert(std::make_pair(1, 1.0));
auto it = m.find(3);
if (it != m.end()) {
it->second += 9;
}
}
It will also be faster because lookup is O(log(n))
You can reach the same complexity with a vector of sorted pairs by using std::lower_bound (or std::equal_range if keys can be repeated)
It depends on your constrains. If you have the unique key (the first element) you can use std::map<K,V> to hold your objects. Then increasing it is easy. If V has a default constructor initializing it to zero, you can even skip adding new elements and just increment (I am not sure it will work with ints through).
std::map<K,V> data;
data[key] = data[key] + 1;
the [] operator used for non-existent key will create the object for you using its default constructor. To just access data use at or find methods.
extending sehe's answer: You can use std::multimap in the same way if you may have duplicate keys. This container also keeps the <K,V> pair in sorted order(keys) so binary search approach obviously speed up things.
There is no exact answer to your question: it depends.
My first answer is: use std::find_if (available in <algorithm>, part of the C++ Standard Library), then profile your code. If the search turns out to be a bottleneck worthy of concern, then try another approach.
Beware of using a std::map, as it will sort the pairs by their first component (that is, the insertion order will be lost). In addition, it will not allow you to store two pairs with the same first component.
As others have mentioned, you can work around this caveats (if they are indeed caveats to your problem), but, like I mentioned before, it would only be worth your while if you demonstrate first that the search turned out to be a bottleneck after using the standard algorithms.