C++11 search an std::map with composite key - c++

I want to implement a function (findn) below that search on the std::map to find an element. However in my case the key is composite value, it is an <int,int>
How do I use the std::map.find here?
#include <iostream>
#include <map>
#include <utility>
#include <string>
using namespace std;
std::map<std::pair<int, int>, std::string> studentMap;
int insert(int i, int j, std::string name) {
if( !studentMap.insert( std::make_pair ( std::make_pair(i,j), name)).second ) {
std::cout << "game not added" << std::endl;
} else {
std::cout << "game added" << std::endl;
}
return 0;
}
void findn(int i, int j) {
// how to find when we have composite key?
}
int main() {
insert(1,1,"test");
insert(1,1,"tes");
insert(1,2,"test 2");
std::cout << studentMap.size() << std::endl;
findn(1,1);
}

This would do the work:
auto it = mymap.find(std::make_pair(i,j));

Related

Sorting a map by values - keys

I'm writing a code that counts the number of occurrences of each word in a file, and print out these words in order of number of occurrences. After each word, it prints its number of occurrences. Words occurring the same number of times in the file are listed in alphabetical order.
I don't know how to modify that code to get the words in order of number of occurrences, and that words occurring the same number of times in the file are listed in alphabetical order.
Limitations: I can use only headers like <iostream>, <map>, <string>, <fstream> and <utility>
Example of how it should work:
In:
one two three one two four two one two
Out:
four 1
three 1
one 3
two 4
By now, I've done something like that:
#include <iostream>
#include <fstream>
#include <map>
#include <string>
typedef std::map<std::string, int> StringIntMap;
void count_words(std::istream &in, StringIntMap &words)
{
std::string text;
while (in >> text)
{
++words[text];
}
}
int main(int argc, char **argv)
{
std::ifstream in("readme.txt");
StringIntMap words_map;
count_words(in, words_map);
for (StringIntMap::iterator it = words_map.begin(); it != words_map.end(); ++it)
{
std::cout << it->first << " " << it->second << std::endl;
}
}
A solution using std::map to perform the sorting.
Readability may be further improved by replacing std::pair<string, int> with a struct with a meaningful name.
#include <fstream>
#include <iostream>
#include <map>
#include <string>
#include <utility>
using std::cout;
using std::ifstream;
using std::map;
using std::pair;
using std::string;
struct Dummy {};
struct Compare {
bool operator()(const pair<string, int> &p1,
const pair<string, int> &p2) const {
if (p1.second < p2.second) {
return true;
} else if (p1.second > p2.second) {
return false;
} else {
return p1.first < p2.first;
}
}
};
int main(int argc, char **argv) {
ifstream in("readme.txt");
map<string, int> occurences;
string word;
while (in >> word) {
occurences[word]++;
}
map<pair<string, int>, Dummy, Compare> sorted;
for (const auto &p : occurences) {
sorted.insert({p, Dummy{}});
}
for (const auto &p : sorted) {
cout << p.first.first << ": " << p.first.second << "\n";
}
}
you can use std::multimap to do the the sort.
int main()
{
std::map<std::string,int> words_map;
count_words(std::cin, words_map);
std::multimap<int,std::string> frequency_map;
for(auto& [word,freq]:words_map){
frequency_map.insert({freq,word});
}
for(auto& [freq,word]:frequency_map){
std::cout << word << ' ' << freq << '\n';
}
}
https://godbolt.org/z/Er7o8Wec1

std::map<int,bool> wrong result of insert?

#include <iostream>
#include <map>
using namespace std;
int main()
{
std::map<int, bool> set;
cout << (int)set.insert({ 5,false }).second << endl;
return 0;
}
I don't know why the result is 1 instead of 0, while second is false.
std::map::insert's return value is an std::pair<iterator, bool> where the bool denotes whether insertion took place. cout << (int)set.insert({ 5,false }).second << endl; will only print whether insertion successfully took place.
To do what you want, you'll want to use the first value in the returned std::pair which is an iterator and then use that to check the value of the new key/value pair that you inserted:
#include <iostream>
#include <map>
int main()
{
std::map<int, bool> set;
std::cout << set.insert({5, false}).first->second << '\n';
return 0;
}

c++ Container that preserve insertion order

I have a std::map which store a key with a vector of std::any.
The purpose is to store all values and print them (with the different types) for each key.
No other operations are performed on the container, only "insertion" and "clean".
I want to clarify that the container is filled (and emptied) very frequently, so i need an efficient container.
It all works with my code. The problem, however, is that when i print the values they are sorted according to the key, but i have to print (or store) them by insertion order.
My code:
#include <iostream>
#include <map>
#include <vector>
#include <any>
std::map<int, std::vector<std::any>> testMap;
void insertMap(int value, std::vector<std::any> tempVector);
void printMap();
int main()
{
std::vector<std::any> tempVector;
tempVector.clear();
tempVector.push_back(1000);
tempVector.push_back((std::string)"hello");
tempVector.push_back(0.10f);
insertMap(10, tempVector);
tempVector.clear();
tempVector.push_back(1500);
tempVector.push_back((std::string)"hello2");
tempVector.push_back(0.20f);
insertMap(5, tempVector);
tempVector.clear();
tempVector.push_back(2000);
tempVector.push_back((std::string)"hello3");
tempVector.push_back(0.5f);
insertMap(7, tempVector);
// etc..
printMap();
}
void insertMap(int value, std::vector<std::any> tempVector)
{
testMap[value].insert(testMap[value].end(), tempVector.begin(), tempVector.end());
}
void printMap()
{
for (const auto& [key, value] : testMap)
{
std::cout << "key=" << key << "\n";
for(auto vec_iter : value)
{
if (vec_iter.type() == typeid(int))
std::cout << "\t" << "int=" << std::any_cast<int>(vec_iter) << "\n";
else if (vec_iter.type() == typeid(float))
std::cout << "\t" << "float=" << std::any_cast<float>(vec_iter) << "\n";
else if (vec_iter.type() == typeid(std::string))
std::cout << "\t" << "string=" << std::any_cast<std::string>(vec_iter) << "\n";
}
}
}
Output:
key=5
key=7
key=10
Expected output:
key=10
key=5
key=7
I tried to using unordered_map but it doesn't print them by insertion order.
So which container could i use? What could be the best performance in my case?
I thought that i could use a std::vector< std::map<int, std::vector<std::any>> > (vector that store std::map). But is it fast? Is there a better solution?
There is no standard library container that both provides fast access by key (which is presumably why you're using std::map to begin with) and "preserves insertion order". If you really need access by key, then iteration order is something you give up control over.
If you need to recover the order of insertion, then you are going to have to preserve it. The simplest way to do that is to just store a vector of map iterators alongside your map. When you insert an item into the map, push the new iterator for it to the back of the vector too.
If you are in a position to use Boost, Boost.MultiIndex can be resorted to:
Live Coliru Demo
#include <iostream>
#include <vector>
#include <any>
#include <utility>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/sequenced_index.hpp>
#include <boost/multi_index/key.hpp>
struct test_map_value_type
{
test_map_value_type(int first, const std::vector<std::any>& second):
first{first},second{second}{}
int first;
mutable std::vector<std::any> second;
};
boost::multi_index_container<
test_map_value_type,
boost::multi_index::indexed_by<
boost::multi_index::ordered_unique<
boost::multi_index::key<&test_map_value_type::first>
>,
boost::multi_index::sequenced<>
>
> testMap;
void insertMap(int value, std::vector<std::any> tempVector);
void printMap();
int main()
{
std::vector<std::any> tempVector;
tempVector.clear();
tempVector.push_back(1000);
tempVector.push_back((std::string)"hello");
tempVector.push_back(0.10f);
insertMap(10, tempVector);
tempVector.clear();
tempVector.push_back(1500);
tempVector.push_back((std::string)"hello2");
tempVector.push_back(0.20f);
insertMap(5, tempVector);
tempVector.clear();
tempVector.push_back(2000);
tempVector.push_back((std::string)"hello3");
tempVector.push_back(0.5f);
insertMap(7, tempVector);
// etc..
printMap();
}
void insertMap(int value, std::vector<std::any> tempVector)
{
auto it=testMap.emplace(value,std::vector<std::any>{}).first;
it->second.insert(it->second.end(), tempVector.begin(), tempVector.end());
}
void printMap()
{
for (const auto& [key, value] : testMap.get<1>())
{
std::cout << "key=" << key << "\n";
for(auto vec_iter : value)
{
if (vec_iter.type() == typeid(int))
std::cout << "\t" << "int=" << std::any_cast<int>(vec_iter) << "\n";
else if (vec_iter.type() == typeid(float))
std::cout << "\t" << "float=" << std::any_cast<float>(vec_iter) << "\n";
else if (vec_iter.type() == typeid(std::string))
std::cout << "\t" << "string=" << std::any_cast<std::string>(vec_iter) << "\n";
}
}
}
Output
key=10
int=1000
string=hello
float=0.1
key=5
int=1500
string=hello2
float=0.2
key=7
int=2000
string=hello3
float=0.5

Run through a vector of member functions in boost for_each

I try to learn boost lambda expressions, and this is a thing that doesn't work out.
How can I run in the for_each a selected member of Holder?
#include <iostream>
#include <string>
#include <boost/assign.hpp>
#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>
using namespace std;
using namespace boost::assign;
using namespace boost::lambda;
class Holder
{
public:
void vRun1(std::string s){ cout << "vRun1 " << s << endl; }
void vRun2(std::string s){ cout << "vRun2 " << s << endl; }
void vRun3(std::string s){ cout << "vRun3 " << s << endl; }
};
// --------------------
std::map< std::string, mem_fun_ref_t<void, Holder> > replacer;
insert(replacer)
("buh", std::mem_fun_ref(&Holder::vRun1))
("mar", std::mem_fun_ref(&Holder::vRun2))
("heu", std::mem_fun_ref(&Holder::vRun3));
Holder hol;
How do I call here the functions I have registered in the map<>?
for_each(replacer.begin(), replacer.end(), /* bind(_1, hol, it.first) */ );
The result should be
vRun1 buh
vRun2 mar
vRun3 heu
It looks as though you are overcomplicating it slightly. I'd use boost::function<> like so:
See it live on http://liveworkspace.org/code/b2c5a38d8c3499eefb6330a839a89d0a
#define BOOST_RESULT_OF_USE_DECLTYPE
#include <iostream>
#include <string>
#include <map>
#include <boost/function.hpp>
#include <boost/foreach.hpp>
#include <boost/phoenix.hpp>
using namespace std;
class Holder {
public:
void vRun1(std::string s){ cout << "vRun1 " << s << endl; }
void vRun2(std::string s){ cout << "vRun2 " << s << endl; }
void vRun3(std::string s){ cout << "vRun3 " << s << endl; }
};
typedef std::map< std::string, boost::function<void(Holder&, std::string)> > Replacer;
int main()
{
Replacer replacer;
replacer["a"] = &Holder::vRun1;
replacer["b"] = &Holder::vRun2;
replacer["c"] = &Holder::vRun3;
Holder hol;
for (Replacer::const_iterator it=replacer.begin(); it != replacer.end(); ++it)
{
(it->second)(hol, it->first);
}
Alternatively:
std::cout << "Using BOOST_FOREACH:\n";
BOOST_FOREACH(Replacer::value_type& pair, replacer)
{
(pair.second)(hol, pair.first);
}
Or even:
std::cout << "Using Boost Phoenix:\n";
namespace phx = boost::phoenix;
using namespace phx::arg_names;
std::for_each(replacer.begin(), replacer.end(),
phx::bind(
phx::bind(&Replacer::value_type::second, arg1),
phx::ref(hol),
phx::bind(&Replacer::value_type::first, arg1)));
}
Outputs
vRun1 a
vRun2 b
vRun3 c
Using BOOST_FOREACH:
vRun1 a
vRun2 b
vRun3 c
Using Boost Phoenix:
vRun1 a
vRun2 b
vRun3 c
This works for me:
#include <iostream>
#include <string>
#include <boost/assign.hpp>
#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>
#include <boost/function.hpp>
using namespace boost::lambda;
class Holder
{
public:
void vRun1(std::string s){ std::cout << "vRun1 " << s << std::endl; }
void vRun2(std::string s){ std::cout << "vRun2 " << s << std::endl; }
void vRun3(std::string s){ std::cout << "vRun3 " << s << std::endl; }
};
// --------------------
typedef std::map <std::string,
boost::function<void(Holder&, std::string)> > Replacer_t;
Replacer_t replacer;
typedef Replacer_t::value_type ReplacerValue_t;
int main()
{
boost::assign::insert(replacer)
(std::string("buh"), &Holder::vRun1)
(std::string("mar"), &Holder::vRun2)
(std::string("heu"), &Holder::vRun3);
Holder hol;
for_each(replacer.begin(),
replacer.end(),
bind(protect(bind(bind(&ReplacerValue_t::second,_2),
_1,
bind(&ReplacerValue_t::first,_2))),
boost::ref(hol), _1));
}
This took about 2 hours of fighting with boost::lambda. In C++11 I would write it in 30 seconds, so update your compilers accordingly.

Stack STL with 2 params

Im implementing a B-tree in C++,I have a stack which saves pairs . my problem is, how i put in this stack because push only accept 1 argument. thanks
Use std::pair provided by the standard library.
You can create them with the function make_pair.
#include <iostream>
#include <stack>
#include <string>
using namespace std;
int main(int argc, char **argv)
{
int myInt = 1;
string myString("stringVal");
stack<pair<string, int> > myStack;
myStack.push(make_pair(myString, myInt));
return 1;
}
#include <stack>
#include <utility>
#include <iostream>
using namespace std;
int main() {
stack <pair<int,int> > s;
s.push( make_pair( 1, 2 ) );
pair <int, int> p = s.top();
cout << p.first << " " << p.second << endl;
}
#include <utility>
// ...
stack<pair<string,string> > s;
s.push(make_pair("roses", "red"));
int main()
{
stack <pair<int,int> > s;
s.push({1,2});
cout << s.top().first << " " << s.top().second;
}