STL <map> allows duplicate pairs? - c++

I have written the following code and was surprised at the output. I heard that <map> avoids collision of keys, but here it appears to allow insertion of duplicate pairs.
#include<iostream>
#include<map>
using namespace std;
int main()
{
map<string,char> namemap;
namemap["yogi"]='c';
namemap.insert(pair<string,char>("yogendra",'a'));
namemap.insert(pair<string,char>("yogendra",'b'));
cout<<namemap["yogendra"]<<endl;
return 0;
}
This code outputs a. You can run it on C++ Shell.
Does avoiding collision means that we cannot enter multiple pairs with same key?

The second insert with the same key is a no-op. It simply returns an iterator pointing to the existing element.
std::map::insert() has a return value, which you should check.
It is of type std::pair<iterator,bool>. The second element of the pair tells you whether the element has been inserted, or whether there was already an existing entry with the same key.
cout << namemap.insert(pair<string,char>("yogendra",'a')).second << endl;
cout << namemap.insert(pair<string,char>("yogendra",'b')).second << endl;

STL map does not allow same Keys to be used. You may want to go for multi-map for that.

a map will not throw any compile/run time error while inserting value using duplicate key. but while inserting, using the duplicate key it will not insert a new value, it will return the same exiting value only. it will not overwrite.
but in the below case it will be overwritten.
map<char,int> m1;
m1.insert(pair <char, int> ('a', 40));
m1['a']=50;
cout << "a => " << m1.find('a')->second << '\n';
The result will be 50.
below example, it will not overwrite.
map<char,int> m1;
m1.insert(pair <char, int> ('a', 40));
m1.insert(pair <char, int> ('a', 50));
cout << "a => " << m1.find('a')->second << '\n';
Result will be 40.
Remember map size 1 here for both the cases.
cout< "size = " << m1.size() << '\n';
it will be 1 in both cases.

Related

frequency <unordered_map> behaviour

i try to implement freq unordered map but it has weird behavior , why when i use unordered_map it gives me keys with negative numbers and when i use map it will give my the correct keys values.
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
int maxOperations(vector<int>& nums, int k) {
unordered_map <int,int> mp;
for(auto i:nums){
mp[i]++;
}
int count=0;
// for(auto i:mp)
// cout << i.first << " " << i.second << endl;
for(auto i:mp){
int target= k-i.first;
cout << i.first << " " << i.second << " "<< mp[target] << endl;
if(i.second>0 && mp[target]>0){
if(i.first!=target){
count += min(i.second,mp[target]);
mp[target]=0;
//i.second=0;
mp[i.first]=0;
}else
{
cout << count << endl;
count += floor(i.second/2);
mp[target]=0;
}
}
}
return count;}
int main()
{
vector<int> vec= {29,26,81,70,75,4,48,38,22,10,51,62,17,50,7,7,24,61,54,44,30,29,66,83,6,45,24,49,42,31,10,6,88,48,34,10,54,56,80,41,19};
int k =12 ;
cout << maxOperations(vec,k);
return 0;
}
When you use an ordered map, you traverse the keys in order. Thus, target is never negative. When you traverse an unordered map, it is unordered. Therefore, target is sometimes negative.
If the negative values are not correct, then you need to traverse the map in order and so you should not use an unordered map.
Another problem with traversing out of order is that when modifying the map while traversing it, you will create entries that may or may not be included in your traversal. That will cause unpredictable behavior. You may prefer to create new entries in a separate container and merge them into the original container only when you're finished traversing.

efficient way to get key from std::map value

I have a map as below :
std::map< std::string ,int> mapobj;
mapobj["one"] = 1;
mapobj["two"] = 2;
mapobj["three"] =3 ;
how to get key when input is value
EX :
input : 1
output : one
Note : In my case value is unique
A one-to-one mapping is actually quite easy, the fastest way to do it is to probably maintain two maps, one for each direction. It becomes more complicated if it's not one-to-one since you'll need to provide a way to get a collection of values or key, rather than a single one. Happily, you only have the one-to-one requirement.
One of the maps is the one you have now, the other will map the values to a given key, soboth would be:
std::map<std::string, int> forwardmapobj;
std::map<int, std::string> reversemapobj;
and these would be maintained within a bidimap class of some sort.
Whenever you insert to, or delete from, your bidimap, you have to perform the equivalent operation on both internal maps.
For example, here's some pseudo-code. It maintains the two maps and ensures that they'e kept in sync for whatever operations you have that change the keys and values:
class biDiMap:
map<string, int> forwardMap
map<int, string> reverseMap
void add(string key, int val):
if exists forwardMap[key]: throw exception 'duplicate key'
if exists reverseMap[val]: throw exception 'duplicate value'
forwardMapObj[key] = val
reverseMapObj[val] = key
void delKey(string key):
if not exists forwardMap[key]: throw exception 'no such key'
delete reverseMap[forwardMap[key]]
delete forwardMap[key]
void delVal(int val):
if not exists reverseMap[val]: throw exception 'no such value'
delete forwardMap[reverseMap[val]]
delete reverseMap[val]
int getValFor(string key): return forwardMap[key]
string getKeyFor(int val): return reverseMap[val]
Obviously, there's plenty of other stuff you could add but that should form the basis. In any case, you've probably got enough work ahead of you turning that into a C++ class :-)
If you don't want to roll your own solution, then Boost has a very good one that you can pretty well use as is. Boost.Bimap provides a fully-templated bi-directional map that you should be able to use with minimal code, such as the following complete program:
#include <iostream>
#include <string>
#include <boost/bimap.hpp>
using std::string;
using std::cout;
using std::exception;
using boost::bimap;
int main()
{
typedef bimap<string, int> SiMap;
typedef SiMap::value_type SiEntry;
SiMap bidi;
bidi.insert(SiEntry("ninety-nine", 99));
int i = 0;
for (string str: {"one", "two" , "three", "four", "five", "six"}) {
bidi.insert(SiEntry(str, ++i));
}
cout << "The number of entries is " << bidi.size() << "\n\n";
for (auto i = 1; i <= 7; i += 3) {
try {
cout << "Text for number " << i << " is " << bidi.right.at(i) << "\n";
} catch (exception &e) {
cout << "Got exception looking up number " << i << ": " << e.what() << "\n";
}
}
cout << "\n";
for (auto str: {"five", "ninety-nine", "zero"}) {
try {
cout << "Number for text '" << str << "' is " << bidi.left.at(str) << "\n";
} catch (exception &e) {
cout << "Got exception looking up text '" << str << "': " << e.what() << "\n";
}
}
cout << "\n";
return 0;
}
It creates a bi-directional mapping between the textual form of a number and the integral value, then does a few lookups (in both directions) to show that it works:
The number of entries is 7
Text for number 1 is one
Text for number 4 is four
Got exception looking up number 7: bimap<>: invalid key
Number for text 'five' is 5
Number for text 'ninety-nine' is 99
Got exception looking up text 'zero': bimap<>: invalid key
I do notice that this has the "stdmap" tag, so this may not be appropriate. However Boost has boost::bimap<> which will allow you to do what you want: it allows lookup by either key or value.
how to get key when input is value
First, there is no guarantee that value is unique. I realize that you are saying it is unique. Still, conceptually speaking, this is something to keep in mind when looking at the problem.
Second, std::map is not sorted by value. Hence, the most efficient algorithm to look for a value will be O(N) on an average.
Try boost Bimap. all the things you are trying to do can simply be done by it.
1 --> one
2 --> two
...
one --> 1
two --> 2
...
here is a link where a working example is present.
here

Implementation of stl map in c++ using class of values

I have to develop stl map in which key is integer where value associated with key is 5 tuple.
having integer data types only.
e.g key=1
value=(2,3,4,5,6)
key=2
value=(1,2,3,4,5)
and so on.
how i can implement it for insert and search operation.
mean how to map single key value to tuple of 5 values.
how to accomplish it?
Depending on what your data means I would go for a different approach.
If your values logically belong together, that is if they only make sense in combination, then I would simply store them in a common data structure and store this data structure in a map. For this purpose a class, struct or container might suit your needs. Again it depends on your context what is the best choice.
If your values exist in isolation and the only connection between them is that they share the same key, then I would use std::multimap.
If you have access to C++11, you can make use of std::tuple (or boost´s tuple), which I believe is the best fit data structure to your case. See the snippet below and see if it fits:
#include<tuple>
#include<map>
#include<iostream>
#include<stdexcept>
typedef std::tuple<int, int, int, int, int > fiveIntTuple;
void insert(std::map<int, fiveIntTuple>& values,
int key, int a, int b, int c, int d, int e){
values[key] = std::make_tuple(a,b,c,d,e);
}
fiveIntTuple search(const std::map<int, fiveIntTuple >& values, int key ){
return values.at(key);
}
void print(const std::map<int, fiveIntTuple >& values, int key){
try{
fiveIntTuple t;
t = search(values, key);
std::cout << "For key == " << key << " got: "
<< std::get<0>(t) << ","
<< std::get<1>(t) << ","
<< std::get<2>(t) << ","
<< std::get<3>(t) << ","
<< std::get<4>(t) << std::endl;
}catch(const std::out_of_range&){
std::cerr << "For key " << key << " ... not found" << std::endl;
}
}
int main(){
std::map<int, fiveIntTuple > my_values;
insert(my_values, 1, 2,3,4,5,6);
insert(my_values, 2, 1,2,3,4,5);
print(my_values, 1);
print(my_values, 2);
print(my_values, 3);
return 0;
}
Executing this snippet you must get:
For key == 1 got: 2,3,4,5,6
For key == 2 got: 1,2,3,4,5
For key 3 ... not found

STL MAP should use find() or [n] identifier to find element in map?

I am confused which is more efficient?
As we can access map directly, why do we need to use find?
I just need to know which way is more efficient.
#include <iostream>
#include <map>
using namespace std;
int main ()
{
map<char,int> mymap;
map<char,int>::iterator it;
mymap['a']=50;
mymap['b']=100;
mymap['c']=150;
mymap['d']=200;
//one way
it=mymap.find('b');
cout << (*it).second <<endl;
//another way
cout << mymap['b'] <<endl;
return 0;
}
thanks in advance! :)
Using find means that you don't inadvertently create a new element in the map if the key doesn't exist, and -- more importantly -- this means that you can use find to look up an element if all you have is a constant reference to the map.
That of course means that you should check the return value of find. Typically it goes like this:
void somewhere(const std::map<K, T> & mymap, K const & key)
{
auto it = mymap.find(key);
if (it == mymap.end()) { /* not found! */ }
else { do_something_with(it->second); }
}
As we can access map directly, why do we need to use find?
Because map<>::operator[] is sometimes nasty. If an element doesn't exist then:
it inserts it
value initialize it
returns reference of value
Thus it always returns a valid reference of value, even if a key din't exist previously. This behavior is not intended many times.
On the other hand map<>::find() is safer; because it returns end(), if a value doesn't exit. Another advantage of find() is that it returns an iterator which contains references to key (first) and value(second) both.
The [] operator in map is not constant it is logarithmic. Most of the books stress on this fact and point out it is a bit misleading. So both find and [] operator are with the same complexity.
Please note that the [] operator will create the entry even if it does not exist while find will return end() in that case.
This code and doc is picked from cplusplus.com
// accessing mapped values
#include <iostream>
#include <map>
#include <string>
using namespace std;
int main ()
{
map<char,string> mymap;
mymap['a']="an element";
mymap['b']="another element";
mymap['c']=mymap['b'];
cout << "mymap['a'] is " << mymap['a'] << endl;
cout << "mymap['b'] is " << mymap['b'] << endl;
cout << "mymap['c'] is " << mymap['c'] << endl;
cout << "mymap['d'] is " << mymap['d'] << endl;
cout << "mymap now contains " << (int) mymap.size() << " elements." << endl;
return 0;
}
OP:
mymap['a'] is an element
mymap['b'] is another element
mymap['c'] is another element
mymap['d'] is
mymap now contains 4 elements.
Notice how the last access (to element 'd') inserts a new element in the map with that key and initialized to its default value (an empty string) even though it is accessed only to retrieve its value. Member function map::find does not produce this effect.

I need to have a key with multiple values. What datastructure would you recommend?

I have an string array filled with words from a sentence.
words[0] = "the"
words[1] = "dog"
words[2] = "jumped"
words[3] = "over"
words[4] = "the"
words[5] = "wall."
words[6] = "the"
words[7] = "cat"
words[8] = "fell"
words[9] = "off"
words[10] = "the"
words[10] = "house."
etc.
(Stupid example, but it works for this)
Each word will be a key with it's following word as it's value. so "over" => "the". Some keys can have multiple values. For example, "the" => "dog" || "wall" || "cat" || "house". The value is randomly chosen from those for that key.
When the program runs it picks a word at random and makes a sentence. So it could be something like: "the cat fell off the dog".
I tried implementing a map (map myMap;) but this allows only one value per key (I think).
Hope I explained this right.
std::multimap
The link provides an excellent example. Quoted below:
int main()
{
multimap<const char*, int, ltstr> m;
m.insert(pair<const char* const, int>("a", 1));
m.insert(pair<const char* const, int>("c", 2));
m.insert(pair<const char* const, int>("b", 3));
m.insert(pair<const char* const, int>("b", 4));
m.insert(pair<const char* const, int>("a", 5));
m.insert(pair<const char* const, int>("b", 6));
cout << "Number of elements with key a: " << m.count("a") << endl;
cout << "Number of elements with key b: " << m.count("b") << endl;
cout << "Number of elements with key c: " << m.count("c") << endl;
cout << "Elements in m: " << endl;
for (multimap<const char*, int, ltstr>::iterator it = m.begin();
it != m.end();
++it)
cout << " [" << (*it).first << ", " << (*it).second << "]" << endl;
}
If you're using C++ then just create a class to represent your key-value pairs:
Class foo {
key : String
values : list of values
}
Then, create a map that maps each key to an object containing its values.
This is simple, extendable, and can be done in any OO-language.
Sorry, my C++ is rusty so the syntax is wrong, but the essential idea is straightforward.
you can use a multimap from the STL and use the call
pair<iterator, iterator> equal_range(const key_type& k)
to get a range of iterators that match your key
personally i find this slightly clunky due to having to deal with iterator ranges rather than just getting an object back that represents all values for that key. to get around that you could also store a vector in a regular map and add your strings to the vector.
I've found that a struct may work well for this situation. This approach (basically akin to a class) allows a cleaner access to your parameters named as you see fit.
struct car_parts {
string wheelType;
string engine;
int number_of_cylinders;
car_parts(string _wheelType, string _engine, int _number_of_cylinders)
{
wheelType = _wheelType;
engine = _engine;
number_of_cylinders = _number_of_cylinders;
}
};
int main()
{
// Populate the dictionary
map<char, car_parts> vehicles =
{
{ 'I', car_parts("All terrain", "X2", 6) },
{ 'C', car_parts("Summer only", "BB", 8) },
{ 'U', car_parts("All terrain", "X3", 4) }
};
map<char, car_parts>::iterator it;
it = vehicles.find('I');
if (it != vehicles.end())
{
cout << "The vehicle with key of I has " << it->second.number_of_cylinders << " cylinders\n";
}
}
There can be an alternate approach to achieve two values per key, especially for the cases when most of the map elements have two values per key. By pairing two values for a key, as mentioned in this link:
std::map<std::string, std::pair<std::int, int> > myMap2
use it in the function as:
#include<iostream>
#include<map>
#include<iterator>
using namespace std;
int main(){
map<string,pair<int,int>>mp;
mp.insert(pair<string,pair<int,int>>("ab",make_pair(50,7)));
mp.insert(pair<string,pair<int,int>>("cd",make_pair(51,8)));
map<string,pair<int,int>>::iterator it;
for(it=mp.begin();it!=mp.end();it++)
cout<<it->first<<" "<<it->second.first<<" "<<it->second.second<<" ";
return 0;
}
As two others pointed out, std::multimap can be your solution.
Also consider std::tr1::unordered_multimap. It is available in VS 2008 seems to have it, GCC has it at least from version 4.3.
You may also use unordered_map<char,vector<string>> which has some benefit over map structure. You can do such insertion if your dictionary is like 'c': "cat", 'c':"car", 'a':apple, 'a':"angus" :
unordered_map<char, vector<string>> char_to_strings_map;
//loop to traverse the dictionary : key:c, value:s
char_to_strings_map[c].emplace_back(s);
//loop ends