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

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

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.

How to apply binary search for searching points/pairs in c++?

I want to search if the pair exists in the vector of pairs using binary search.
Here is my code: This code is only looking for the first value in pair:
Could you modify this code that it will be looking for the exact pair?
#include <bits/stdc++.h>
using namespace std;
struct compare {
bool operator()(const pair<int, int>& value,
const int& key)
{
return (value.first < key);
}
bool operator()(const int& key,
const pair<int, int>& value)
{
return (key < value.first);
}
};
int main()
{
vector<pair<int, int> > vect;
vect.push_back(make_pair(1, 20));
vect.push_back(make_pair(3, 42));
vect.push_back(make_pair(4, 36));
vect.push_back(make_pair(2, 80));
vect.push_back(make_pair(7, 50));
vect.push_back(make_pair(9, 20));
vect.push_back(make_pair(3, 29));
sort(vect.begin(), vect.end());
// printing the sorted vector
cout << "KEY" << '\t' << "ELEMENT" << endl;
for (pair<int, int>& x : vect)
cout << x.first << '\t' << x.second << endl;
// searching for the key element 3
cout << "search for key 3 in vector" << endl;
if (binary_search(vect.begin(), vect.end(),
3, compare()))
cout << "Element found";
else
cout << "Element not found";
return 0;
}
If you want to look for an exact pair, you need to provide the pair to binary_search, like this
if (std::binary_search(vect.begin(), vect.end(), std::pair{3, 42}))
// ... found
Note that you don't need the custom compare function here. The default comparator does the right thing. (In fact, you should use the same comparator as used to sort the elements in the first place, otherwise binary_search will be broken).
Note that pre c++17, you need to provide the template arguments to pair, like this,
if (std::binary_search(vect.begin(), vect.end(), std::pair<int,int>{3, 42}))
// ... found
If you want to find the position of the found element, you can use lower_bound like so,
auto lb = std::lower_bound(vect.begin(), vect.end(), std::pair<int,int>{3, 42});
if (lb != vect.end())
std::cout << "Element found at position "
<< std::distance(vect.begin(), lb);
Also, please don't use #include <bits/stdc++.h> or using namespace std;

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

c++ map finding value and associated key

I develop one program in c++ in which i have to find key in stl map by using values.
But values assigned to key is the 5 tuples (srcip,port,destip,port,srcno)
Now i want to check in map whether there is key assosiated with values.
I am trying something like this.
But its showing error like
wrong number of template argument.
Note(In my program in pair key->Value) value consist of tuple of 5 variable.
template<class T>
struct map_data_compare : public std::binary_function<typename T::value_type,typename T::mapped_type,bool>
{
public:
bool operator() (typename T::value_type &pair,typename T::mapped_type i)
{
return pair.second == i;
}
}
class Values
{
private:
std::string C_addr;
int C_port;
std::string S_addr;
int S_port;
int C_ID;
public:
Values(std::string,int,std::string,int,int);
void printValues();
};
Values :: Values(std::string Caddr,int Cport,std::string Saddr,int Sport,int Cid)
{
C_addr=Caddr;
C_port=Cport;
S_addr=Saddr;
S_port=Sport;
C_ID=Cid;
}
void Values::printValues()
{
cout << C_addr<<":" <<C_port<<":" << S_addr <<":" <<S_port << ":"<<C_ID <<endl;
}
//In main
{
typedef std::map<int, Values> itemsType;
itemsType items;
Values connection (inet_ntoa(clientaddr.sin_addr),ntohs(clientaddr.sin_port),inet_ntoa(servaddr.sin_addr),ntohs(servaddr.sin_port),clientID);
std::map<std::int,Values>::iterator it = std::find_if( items.begin(), items.end(), std::bind2nd(map_data_compare<itemsType>(),connection));
if ( it != items.end() )
{
assert( connection == it->second);
std::cout << "Found index:" << it->first << " for values:" << it->second << std::endl;
}
else
{
std::cout << "Did not find index for values:" << connection <<endl;
}
I develop one program in c++ in which i have to find key in stl map by using values.
That's not what maps are meant for. If you need that kind of access, I recommend Boost.Bimap
If the 'key' must be unique, maybe you can try combine the key and value into a std::pair and push them into std::set.
Otherwise you should set your key as value and value as key since you seems mainly use your original value as what we treat to a "key". Then you could use the built-in map::find() function

STL <map> allows duplicate pairs?

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.