Add values to a std::multimap - c++

I'm trying to print out the five most used values. But when I changed my map to a multimap I broke the code where I add values to the map. How can I add values to a multimap? Can it be done in a similar way as I add values to a map?
// Create a map for keeping track of how many occurences of the different colors
multimap<string, int> hexmap;
// Add the hex values to the map
for(int i = 0; i < imagesize; i ++)
{
hexmap[colors[i]]++;
}
typedef std::multimap<int, string> Mymap;
Mymap dst;
std::transform(hexmap.begin(), hexmap.end(),
std::inserter(dst, dst.begin()),
[](const std::pair<string,int> &p )
{
return std::pair<int, string>(p.second, p.first);
}
);
Mymap::iterator st = dst.begin(),it;
size_t count = 5;
for(it = st; ( it != dst.end() ) && ( --count ); ++it)
std::cout << it->second << it->first << endl;

You add elements to a std::multimap<K, V> using insert() or emplace(), e.g.:
std::multimap<std::string, int> map;
map.insert(std::make_pair("hello" , 1));
map.insert({ "world", 0 });
map.emplace("hello", 0);
You'd locate objects in the std::multimap<K, V> using it's find() member, e.g.:
std::multimap<std::string, int>::iterator it = map.find("hello");

"I'm trying to print out the five most used values."
In this case, you don't have to use hexmap as std::multimap just std::map will do the job
However std::multimap for dst should be required

Related

Nested Map, accesing inner map value

For example I have a map like this:
map<string , map <int , int>> example;
and an iterator:
map<string , map <int, int>>::iterator iter;
string word;
And i want to access to the inner map :
for(iter = example.begin();iter!=example.end;iter++){
iter = Map.find(word);
iter -> second //
}
What i should do to access the inner map just for example if iter->second ==4 -it's is not correct ,
or can i do (iter->second)->second ??? can u give me an advise. i undestand that iterator is giving me a pair of (int,int) so i tryed to do another iterator map ::iterator i; and to assing iter->second = i, but it didin't help me to;
For complex types use typedef it will make your life much easier:
typedef std::map< int, int > Ints;
typedef std::map< std::string, Ints > String2Ints;
String2Ints example;
std::string word;
String2Ints::iterator it = example.find( word );
if( it != example.end() ) {
Ints &innerMap = it->second;
Ints::iterator innerit = innerMap.find( 4 );
if( innerit != innerMap.end() )
std::cout << "found value for word " << word << " 4 - " << innerit->second << std::endl;
}
Also your loop and find inside is incorrect, you should either iterate over map or search for value by find(), what you do in your code does not make any sense (technically infinite loop if word is found)
iter->second is a map, so if you want to find something in it you need another find.
You can also use your iterator directly, without the for loop.
Ex:
map<string , map <int, int>>::iterator iter;
iter = example.find(word);
if (iter != example.end()){
map<int, int>>::iterator innerIter;
int key = 4;
innerIter = iter->second.find(key);
if (innerIter != iter->second.end()){
(...)
}
}

Top 5 values from std::map

I have a function already that takes out the key value with the most mapped value.
// Function for finding the occurances of colors or in this case hex values
void findOccurrances(double * mostNumTimes, map<string, int> &hexmap, string * colorlist)
{
map<string,int>::iterator it = hexmap.begin();
for( ;it != hexmap.end(); it ++)
{
if(*mostNumTimes <= it->second)
{
*mostNumTimes = it->second;
*colorlist = it->first;
}
}
}
Is there an easy way to expand it to show the top five results?
I know you can copy it to a vector and what not but I'm wanting an easier way of doing it.
Copying into a vector isn't that difficult:
typedef std::pair<string, int> Pair;
std::vector<Pair> contents(hexmap.begin(), hexmap.end());
Done.
But to find the top 5, believe it or not <algorithm> has a function template that does exactly what you want. In C++11, which usefully has lambdas:
std::vector<Pair> results(5);
std::partial_sort_copy(
hexmap.begin(), hexmap.end(),
results.begin(), results.end(),
[](const Pair &lhs, const Pair &rhs) { return lhs.second > rhs.second; }
);
results now contains the top 5 entries in descending order.
I have a little bit confused about the arguments. why you write the function in this way, And I try for this.
string colorlist;
double max_val = 0;
for (int i = 0; i < 5; ++i)
{
findOccurrances(&max_val, hexmap, &colorlist);
cout << colorlist << " " << max_val << endl; // to do something
mapStudent.erase(colorlist);
}
I'd interchange the key and value and create new map
std::map<int,std::string> dst;
std::transform(hexmap.begin(), hexmap.end(),
std::inserter(dst, dst.begin()),
[](const std::pair<std::string,int> &p )
{
return std::pair<int,std::string>(p.second, p.first);
}
);
And now print top five values of dst in usual way,
typedef std::map<int, std::string> Mymap;
Mymap::iterator st = dst.begin(), it;
size_t count = 5;
for(it = st; ( it != dst.end() ) && ( --count ); ++it)
std::cout << it->second << it->first <<std::endl ;
Edit:
Use a std::multimap if there are same int (value) for more than one std::string (key) in your hexmap

How can i get the top n keys of std::map based on their values?

How can i get the top n keys of std::map based on their values?
Is there a way that i can get a list of say for example the top 10 keys with the biggest value as their values?
Suppose we have a map similar to this :
mymap["key1"]= 10;
mymap["key2"]= 3;
mymap["key3"]= 230;
mymap["key4"]= 15;
mymap["key5"]= 1;
mymap["key6"]= 66;
mymap["key7"]= 10;
And i only want to have a list of top 10 keys which has a bigger value compared to the other.
for example the top 4 for our mymap is
key3
key6
key4
key1
key10
note:
the values are not unique, actually they are the number of occurrences of each key. and i want to get a list of most occurred keys
note 2:
if map is not a good candidate and you want to suggest anything, please do it according to the c++11 ,i cant use boost at the time.
note3:
in case of using std::unordered_multimap<int,wstring> do i have any other choices?
The order of a map is based on its key and not its values and cannot be reordered so it is necessary to iterate over the map and maintain a list of the top ten encountered or as commented by Potatoswatter use partial_sort_copy() to extract the top N values for you:
std::vector<std::pair<std::string, int>> top_four(4);
std::partial_sort_copy(mymap.begin(),
mymap.end(),
top_four.begin(),
top_four.end(),
[](std::pair<const std::string, int> const& l,
std::pair<const std::string, int> const& r)
{
return l.second > r.second;
});
See online demo.
Choosing a different type of container may be more appropriate, boost::multi_index would be worth investigating, which:
... enables the construction of containers maintaining one or more indices with different sorting and access semantics.
#include <iostream>
#include <map>
#include <vector>
#include <algorithm>
#include <string>
using namespace std;
int main(int argc, const char * argv[])
{
map<string, int> entries;
// insert some random entries
for(int i = 0; i < 100; ++i)
{
string name(5, 'A' + (char)(rand() % (int)('Z' - 'A') ));
int number = rand() % 100;
entries.insert(pair<string, int>(name, number));
}
// create container for top 10
vector<pair<string, int>> sorted(10);
// sort and copy with reversed compare function using second value of std::pair
partial_sort_copy(entries.begin(), entries.end(),
sorted.begin(), sorted.end(),
[](const pair<string, int> &a, const pair<string, int> &b)
{
return !(a.second < b.second);
});
cout << endl << "all elements" << endl;
for(pair<string, int> p : entries)
{
cout << p.first << " " << p.second << endl;
}
cout << endl << "top 10" << endl;
for(pair<string, int> p : sorted)
{
cout << p.first << " " << p.second << endl;
}
return 0;
}
Not only does std::map not sort by mapped-to value (such values need not have any defined sorting order), it doesn't allow rearrangement of its elements, so doing ++ map[ "key1" ]; on a hypothetical structure mapping the values back to the keys would invalidate the backward mapping.
Your best bet is to put the key-value pairs into another structure, and sort that by value at the time you need the backward mapping. If you need the backward mapping at all times, you would have to remove, modify, and re-add each time the value is changed.
The most efficient way to sort the existing map into a new structure is std::partial_sort_copy, as (just now) illustrated by Al Bundy.
since the mapped values are not indexed, you would have to read everything and select the 10 biggest values.
std::vector<mapped_type> v;
v.reserve(mymap.size());
for(const auto& Pair : mymap)
v.push_back( Pair.second );
std::sort(v.begin(), v.end(), std::greater<mapped_type>());
for(std::size_t i = 0, n = std::min<int>(10,v.size()); i < n; ++i)
std::cout << v[i] << ' ';
another way, is to use two maps or a bimap, thus mapped values would be ordered.
The algorithm you're looking for is nth_element, which partially sorts a range so that the nth element is where it would be in a fully sorted range. For example, if you wanted the top three items in descending order, you'd write (in pseudo C++)
nth_element(begin, begin + 3, end, predicate)
The problem is nth_element doesn't work with std::map. I would therefore suggest you change your data structure to a vector of pairs (and depending on the amount of data you're dealing with, you may find this to be a quicker data structure anyway). So, in the case of your example, I'd write it like this:
typedef vector<pair<string, int>> MyVector;
typedef MyVector::value_type ValueType;
MyVector v;
// You should use an initialization list here if your
// compiler supports it (mine doesn't...)
v.emplace_back(ValueType("key1", 10));
v.emplace_back(ValueType("key2", 3));
v.emplace_back(ValueType("key3", 230));
v.emplace_back(ValueType("key4", 15));
v.emplace_back(ValueType("key5", 1));
v.emplace_back(ValueType("key6", 66));
v.emplace_back(ValueType("key7", 10));
nth_element(v.begin(), v.begin() + 3, v.end(),
[](ValueType const& x, ValueType const& y) -> bool
{
// sort descending by value
return y.second < x.second;
});
// print out the top three elements
for (size_t i = 0; i < 3; ++i)
cout << v[i].first << ": " << v[i].second << endl;
#include "stdafx.h"
#include <iostream>
#include <vector>
#include <map>
#include <string>
#include <algorithm>
#include <cassert>
#include <iterator>
using namespace std;
class MyMap
{
public:
MyMap(){};
void addValue(string key, int value)
{
_map[key] = value;
_vec.push_back(make_pair(key, value));
sort(_vec.begin(), _vec.end(), Cmp());
}
vector<pair<string, int> > getTop(int n)
{
int len = min((unsigned int)n, _vec.size());
vector<Pair> res;
copy(_vec.begin(), _vec.begin() + len, back_inserter(res));
return res;
}
private:
typedef map<string, int> StrIntMap;
typedef vector<pair<string, int> > PairVector;
typedef pair<string, int> Pair;
StrIntMap _map;
PairVector _vec;
struct Cmp:
public binary_function<const Pair&, const Pair&, bool>
{
bool operator()(const Pair& left, const Pair& right)
{
return right.second < left.second;
}
};
};
int main()
{
MyMap mymap;
mymap.addValue("key1", 10);
mymap.addValue("key2", 3);
mymap.addValue("key3", 230);
mymap.addValue("key4", 15);
mymap.addValue("key6", 66);
mymap.addValue("key7", 10);
auto res = mymap.getTop(3);
for_each(res.begin(), res.end(), [](const pair<string, int> value)
{cout<<value.first<<" "<<value.second<<endl;});
}
The simplest solution would be to use std::transform to build
a second map:
typedef std::map<int, std::string> SortedByValue;
SortedByValue map2;
std::transform(
mymap.begin(), mymap.end(),
std::inserter( map2, map2.end() ),
[]( std::pair<std::string, int> const& original ) {
return std::pair<int, std::string>( original.second, original.first );
} );
Then pick off the last n elements of map2.
Alternatively (and probably more efficient), you could use an
std::vector<std::pair<int, std::string>> and sort it
afterwards:
std::vector<std::pair<int, std::string>> map2( mymap.size() );
std::transform(
mymap.begin(), mymap.end()
map2.begin(),
[]( std::pair<std::string, int> const& original ) {
return std::pair<int, std::string>( original.second, original.first );
} );
std::sort( map2.begin(), map2.end() );
(Note that these solutions optimize for time, at the cost of
more memory.)

C++, Order map content based on second iter

I have map as below
string word;
int occurance;
std::map< std::string, std::map<string, int> > map;
map[word]["count"] = occurance;
map output using iterator.
for(auto outer_iter=map.begin(); outer_iter!=map.end(); ++outer_iter) {
for(auto inner_iter=outer_iter->second.begin(); inner_iter!=outer_iter->second.end(); ++inner_iter) {
std::cout << outer_iter->first << '\t' << inner_iter->second << std::endl;
}
}
I want to display map by ordering the inner_iter->second value.
How can I do it?
The simplest approach to use (unless profiling indicates otherwise) is to simply make an inside-out map when you need to print:
std::multimap<int, std::string> inverse_map;
for(auto outer_iter=map.begin(); outer_iter!=map.end(); ++outer_iter)
{
for(auto inner_iter=outer_iter->second.begin(); inner_iter!=outer_iter->second.end(); ++inner_iter)
{
inverse_map.insert(std::make_pair(inner_iter->second, outer_iter->first));
}
}
Then you just loop through the inverted map and print normally.
EDIT: I think you can get the double sorting you want by instead using a set of pairs:
std::set<std::pair<int, std::string> > inverse_map;
for(auto outer_iter=map.begin(); outer_iter!=map.end(); ++outer_iter)
{
for(auto inner_iter=outer_iter->second.begin(); inner_iter!=outer_iter->second.end(); ++inner_iter)
{
inverse_map.insert(std::make_pair(inner_iter->second, outer_iter->first));
}
}
You can insert into a vector and sort the contents accordingly.
Edit: Modified to sort from highest to lowest.
typedef std::pair<std::string, int> hist_item;
std::vector<hist_item> hist;
hist.reserve(map.size());
for(auto outer_iter=map.begin(); outer_iter!=map.end(); ++outer_iter) {
for(auto inner_iter=outer_iter->second.begin();
inner_iter!=outer_iter->second.end(); ++inner_iter) {
hist.push_back(std::make_pair(outer_iter->first, inner_iter->second));
}
}
std::sort(hist.begin(), hist.end(),
[](const hist_item &a,const hist_item &b){return a.second>b.second;});
for (auto i = hist.begin(); i!= hist.end(); ++i) {
std::cout << i->first << '\t' << i->second << std::endl;
}
This mimics your original output. I am not sure of the purpose of the inner map. If you are tracking properties other than "count" in it, your original output and this routine loses that association, and you just get multiple numbers associated with the outer word.
If you're open to using Boost, you can use Boost::Bimap, which lets you associate words with counts, and counts with words (at the same time). This example shows how to compute the word count of a text and displays the histogram.
If you only need to display the sorted word count occasionally, it might be faster to use a regular std::map for building the word count map. Then you generate the sorted word count as needed using the techniques shown in the other answers. You'll probably have to run benchmarks to know which is faster.
For the sake of completeness, I'll add another solution that uses a heapsort by pushing the maps pairs through a std::priority_queue to obtain the word count sorted by occurrence:
#include <iostream>
#include <map>
#include <queue>
typedef std::map<std::string, int> MyMap;
struct OrderByOccurence
{
bool operator()(MyMap::const_reference lhs, MyMap::const_reference rhs)
{
// This will make the priority queue sort from highest word count
// to lowest.
return lhs.second < rhs.second;
// This will make the priority queue sort from lowest word count
// to highest.
// return rhs.second < lhs.second;
// Here, you can also check that if both counts are the same,
// the elements should be ordered alphabetically by word.
}
};
int main()
{
MyMap m = {{"a", 1}, {"b", 2}, {"c", 3}};
std::priority_queue<std::pair<std::string, int>,
std::vector< std::pair<std::string, int> >,
OrderByOccurence> q;
for (auto it=m.begin(); it!=m.end(); ++it)
q.push(*it);
while (!q.empty())
{
std::cout << q.top().first << " " << q.top().second << "\n";
q.pop();
}
}

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