c++ map clear inside a map - c++

I have the following typedefs
typedef map<string, IPAddressPolicyRulesInfo> SecondMap;
typedef map<string, SecondMap> FirstMap;
FirstMap CPCRF::m_mIMSI2PCRFInfo;
Within the c++ function:
within the function, i want to clear the 2nd map. Which is the best way to do this ? Any comments or suggestions are appreciated.
thanks
pdk

Hopefully this might get you started in the right direction:
#include <map>
#include <iostream>
// In general you shouldn't use _t after your own types (some people don't like it)
// But for a post here it doesn't matter too much.
typedef std::map<int, double> map1_t;
typedef std::map<int, map1_t> map2_t;
typedef map2_t::iterator it_t;
int main(int argc, char** argv)
{
// Create the map
map2_t m;
// Add some entries
{ map1_t h; h[0] = 1.1; h[1] = 2.2; m[5] = h; }
{ map1_t h; h[0] = 5.2; h[8] = 7.2; m[1] = h; }
// Output some information
std::cout << m.size() << std::endl;
std::cout << m[5].size() << std::endl;
// For each element in the outer map m
for (it_t it = m.begin(); it != m.end(); ++it)
{
// Assign a friendly name to the inner map
map1_t& inner = it->second;
// Clear the inner map
inner.clear();
}
// Output some information (to show we have done something)
std::cout << m.size() << std::endl;
std::cout << m[5].size() << std::endl;
return 0;
}

Related

How to have access using pointers on two type definition vectors

I'm trying to learn how I can use the different typedef vector, and after creating them how I can access the variables. I have commented as I wrote the code
#include <iostream>
#include <vector>
//#include <stdlib.h>
using namespace std;
//Here I wanted to created a structure where I have position vector
struct Point {
double pos;
};
// now I have the type vector definitons named List
typedef std::vector<Point> List;
int main()
{
//I have initialized two list which are List A, and List B
List A;
List B;
//Point a, and Point b are two double data type variables that I want to push back into the two kind of list
Point a;
Point b;
for(int i =0; i<100; i ++){
a.pos = 2*i+1;
b.pos = 2*i -1;
A.push_back(a);
B.push_back(b);
}
return 0;
}
Now my question is how I can access the variables from the two List that I have created. I want to have access to the same index vector.
This is how I tried with dereferencing the pointer, but I think I'm making some mistakes:
for (List::iterator it = A->begin(); it != A->end(); it++) {
Point* val = &(*it);
cout << val->pos()<<endl;
//I need to access the value from B list too
}
Here is the code that would work (assuming A and B are the same length):
size_t jj = 0;
for (List::iterator it = A.begin(); it != A.end(); it++) {
cout << it->pos<<endl;
cout << (B.begin() + jj)->pos<< endl;
jj++;
}
Note that A and B are not pointers so you access their methods normally. By the way, if you have access to C++11 and above, you can use the following:
size_t ii = 0;
for (const auto& el: A) {
cout << el.pos << "," << B.at(ii).pos << endl;
ii++;
}
This has nothing to do with vectors, typedefs or anything else.
val->pos is a double, not a function.
So, remove the ():
Point* val = &(*it);
cout << val->pos << endl;
Or, a little more neatly:
const Point& val = *it;
std::cout << val.pos << '\n';

Map reference confusion

I encountered with some weird problem. I have class which store its values inside map. But in one case I need to expose map to do some external calculation and possible adding of data inside that map.
And I have next problem. I have shared_ptr of that class and expose map through reference, but during processing map wont accept new data.
I wrote some dummy example of that just to be clear. What is happening here? And why?
Why changes made to map won't hold up after function end?
#include <map>
#include <iostream>
#include <memory>
class MapWrap {
public:
MapWrap() {}
~MapWrap(){}
std::map<int, int>& getMap() { return map; }
private:
std::map<int, int> map;
};
void goGo(std::shared_ptr<MapWrap> m){
auto map = m->getMap();
std::cout << "Func: before: map size: " << map.size() << std::endl;
for(int i = 0; i < 3; ++i){
// This should and will add new value to map.
if(map[i] == 3){
std::cout << "blah" << std::endl;
}
}
std::cout << "Func: after: map size: " << map.size() << std::endl;
}
int main(){
auto mapWrap = std::make_shared<MapWrap>();
for(int i = 0; i < 3; ++i){
goGo(mapWrap);
}
return 0;
}
EDIT: Removed const from getMap() method.
The problem is that here:
auto map = m->getMap();
type of map is std::map<int, int> so you make a copy and you modify this copy. Change it to :
auto& map = m->getMap();
and you will modify the passed map instead of copy.
btw. if you dont know what type your auto variable have, you can always use compiler errors to check this:
template<typename T> struct TD;
auto map = m->getMap();
TD<decltype(map)> dd;
will result in:
main.cpp:19:21: error: aggregate 'TD<std::map<int, int> > dd' has incomplete type and cannot be defined
TD<decltype(map)> dd;
here you can read map type is std::map<int, int>

Obtaining smallest key in a std::map

I need to get the smallest element in a std::map. I'm aware that there is plenty of documentation available; however, I can't seem to get any to work.
I have two maps, bid and ask, both of which are properties of the Book class. Each is a map of queues. Each of these queues hold Order objects (which have various properties like price, volume, etc.). I have a member function update which obtains the best bid, best ask, and the spread:
void update(void)
{
unsigned long long highest_bid, lowest_ask = 0;
for (std::map<unsigned long long, queue<Order>>::iterator it = this->bid.begin(); it != this->bid.end(); ++it)
{
highest_bid = it->first;
}
// best ask code here
this->bestBid = highest_bid;
this->bestAsk = lowest_ask;
this->spread = labs(this->bestAsk - this->bestBid);
}
Where the ask code is, I've tried the following:
lowest_ask = this->ask.begin()->first;
This compiles, but when I debug it throws an assertion failure (which I've read up on other questions here and can't seem to understand):
Expression: map/set iterator not dereferencable
I've tried reverse iteration:
for(std::map<unsigned long long, queue<Order>>::reverse_iterator rit = this->ask.rbegin(); rit != this->ask.rend(); ++rit)
{
lowest_ask = rit->first;
}
Which compiles and debugs fine, but lowest_ask is always 0, which is wrong. When I step through it in the debugger it doesn't stop until it reaches zero.
I've tried swapping the iterators around:
for(std::map<unsigned long long, queue<Order>>::reverse_iterator rit = this->ask.rend(); rit != this->ask.rbegin(); ++rit)
{
lowest_ask = rit->first;
}
This compiled fine, but once again threw the debug assertion failure.
I could continue on and on on what I've tried, but this question is already over-complicated. I just don't understand why I can't just do what I did at the start (lowest_ask = this->ask.begin()->first).
Thank you very much in advance.
Iterating through the map and always assigning the same variable seems like needlessly hard work.
If you need to access the first item in the map (or the last item in the map) then begin() (or rbegin()) is all you need.
std::map <int, int> themap;
themap[4] = 1;
themap[2] = 2;
themap[1] = 3;
themap[6] = 4;
themap[5] = 5;
themap[7] = 6;
if (!themap.empty())
{
std::cout << "item[" << themap.begin()->first << "] = " << themap.begin()->second << std::endl;
std::cout << "item[" << themap.rbegin()->first << "] = " << themap.rbegin()->second << std::endl;
}
the only time you need to be careful with begin and rbegin is when your map is empty
I think you may just need to check that your containers are not empty so that begin() and rbegin() return something meaningful (defined).
Try this:
void update(void)
{
if(bid.empty() || ask.empty())
return;
// best ask code here
this->bestBid = bid.rbegin()->first;
this->bestAsk = ask.begin()->first;
this->spread = labs(this->bestAsk - this->bestBid);
}
This is not "complicated"; it simply takes some standard debugging measures
#include <map>
#include <iostream>
#include <algorithm>
#include <random>
#include <string>
#include <queue>
namespace mock {
using Order = std::string;
struct Book {
using key_type = unsigned long long;
using order_queue_type = std::queue<Order>;
using property_type = std::map<key_type, order_queue_type>;
property_type bids, asks;
void diagnose(const property_type& prop) {
for (auto it = prop.cbegin(); it != prop.cend(); ++it) {
std::clog << "\t" << it->first << '\n';
}
}
void diagnose() {
std::clog << "bids:" << '\n';
diagnose(bids);
std::clog << "asks:" << '\n';
diagnose(asks);
}
Book() {
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<key_type> ba_dist(0, 1000);
std::uniform_int_distribution<std::size_t> len_dist(0, 10);
auto prop_gen = [&] (property_type& prop) {
auto count = len_dist(gen);
for (std::size_t i = 0; i < count; ++i) {
auto val = ba_dist(gen);
auto pair = prop.emplace(val, order_queue_type());
if (!pair.second) {
std::clog << val << " already present" << '\n';
}
}
};
prop_gen(bids);
prop_gen(asks);
}
};
}
int main() {
mock::Book book;
book.diagnose();
}
Instead of the generator in my Book ctor, use your init routines, of course, and your Order type.

Map of Map data struct confusion

I am trying to setup a map of map structure in C++ but can't make it work as expected. I put together this sample program to illustrate the issue. Please excuse the mess if it seems convoluted but I want to preserve the case as much as I can.
So the current print out is: L1, size = 0
and what I was expecting is something like:
L1, size 1
L2, 4
It seems like the second level map is not established properly, maybe a scoping issue, but I can't quite figure it out. The program is as the following:
// So the map is
// AKEY -> { BKEY -> [ SegPair, SegPair .... ] }
#include <map>
#include <utility>
#include <iostream>
#include <vector>
typedef std::string AKEY;
typedef std::string BKEY;
typedef std::pair<int,int> SegPair;
typedef std::vector<SegPair> SegVec;
typedef std::map<BKEY, SegVec> Ensemble;
typedef std::map<AKEY, Ensemble> Oracle;
using std::string;
Oracle o = Oracle();
void setup(string akey, string bkey, int x, int y) {
auto pos = o.find(akey);
if (pos == o.end()) {
o[akey] = Ensemble();
}
Ensemble e = o[akey];
auto pos2 = e.find(bkey);
if (pos2 == e.end()) {
e[bkey] = SegVec();
}
SegPair p(x, y);
e[bkey].push_back(p);
}
int main(void) {
setup("L1", "L2", 3, 4);
for (auto it = o.begin(); it != o.end(); it++) {
std::cout << it->first;
Ensemble e = it->second;
std::cout << ", size = " << e.size() << "\n";
for (auto it2 = e.begin(); it2 != e.end(); it2++) {
std::cout << "\t" << it2-> first << "\n";
SegVec v = it2->second;
for (int i = 0; i < v.size(); i++)
std::cout<< v[i].second << " ";
}
}
}
I think your problem is with this line:
Ensemble e = o[akey];
You're creating a local, rather than capturing the lvalue in the map by reference, for mutation. Thus, any changes you make to e after that point will simply be discarded when e goes out of scope.
In setup, e is a copy of the object in o.
When you modify it, you're not modifying anything in o.
To fix, use a reference:
Ensemble& e = o[akey];
That will make e refer to the same thing as o[akey] instead of a copy.

Vector point to another vector

What I have here is two arrays of different types that I'm converting to vectors.
int ham_array[] = {32,71,12,45,26};
char word_array[] = {"cat", "bat", "green", "red", "taxi"};
vector < int > hamvector (ham_array, ham_array + 5);
vector < char > wordvector(word_array, word_array + 5);
I am going to call a sort function to sort the elements of ham_array from least to greatest. At the same time, I would like the word_array to also get sorted the same way ham_vector gets sorted using references.
For example,
after I call sort(hamvector)
ham_array[] = {12, 26, 32, 45, 71}
and sort(wordvector)
word_array[] = {"green", "taxi", "cat", "red", "bat"};
Is there an easy way to do this?
Well for one thing, that would be char *word_array[], the way you declared it would be a string.
Anyway the way to do this is you declare a structure to keep these things paired:
struct t {string name; int number;};
vector<t> list;
// fill in list
// comparer to compare two such structs
bool comparer(t &a, t &b) { return a.number>=b.number; }
// and to sort the list
sort(list.begin(), list.end(), comparer);
If by simple, you mean a more direct way then yes. The std::sort() does support sorting of raw arrays as well:
sort(word_array, word_array + 5, wordcmp);
As Blindy showed, you need a comparator function to tell sort how the ordering is suppose to be done for your list of words. Otherwise you'll end up sorting by the memory address that the string resides at instead of by the letters in your string. Something like this should work:
int wordcmp(const char *lhs, const char *rhs)
{
return strncmp(lhs, rhs, 256) < 0;
}
One other note, in practice you'll want to prefer std::vector over just raw pointer arrays since the latter isn't as safe.
I've tried to find a solution to a similar problem before and ultimately had to sort it manually. Another way I imagine you could do this would be to write a sorter functor that can somehow figure out, based on which string is being sorted, which integer is associated, and sort based on that. This is terribly inefficient, so I would highly advise doing your own manual sorting using std::swap.
#include <map>
#include <string>
#include <vector>
#include <algorithm>
#include <iostream>
template<typename KeyType, typename ValueType>
class CMappedSorter
{
std::map<KeyType, ValueType>* const m_Mappings;
public:
CMappedSorter(std::map<KeyType, ValueType>* Mappings) : m_Mappings(Mappings)
{
}
bool operator()(KeyType& LHS, KeyType& RHS)
{
const ValueType LHSSortingValue = m_Mappings->find(LHS)->second;
const ValueType RHSSortingValue = m_Mappings->find(RHS)->second;
return (LHSSortingValue < RHSSortingValue);
}
};
int main(int argc, char* argv[])
{
std::vector<int> Integers;
std::vector<std::string> Strings;
Integers.push_back(3);
Integers.push_back(1);
Integers.push_back(2);
Strings.push_back("Apple");
Strings.push_back("Banana");
Strings.push_back("Cherry");
std::map<std::string, int> Mappings;
if(Integers.size() == Strings.size())
{
const unsigned int ElementCount = Strings.size();
// Generate mappings.
auto StringsIterator = Strings.begin();
auto IntegersIterator = Integers.begin();
for(unsigned int i = 0; i < ElementCount; ++i)
{
Mappings[*(StringsIterator)] = *(IntegersIterator);
++StringsIterator;
++IntegersIterator;
}
// Print out before sorting.
std::cout << "Before Sorting" << std::endl;
std::cout << "Int\tString" << std::endl;
StringsIterator = Strings.begin();
IntegersIterator = Integers.begin();
for(unsigned int i = 0; i < ElementCount; ++i)
{
std::cout << *(IntegersIterator) << '\t' << *(StringsIterator) << std::endl;
++StringsIterator;
++IntegersIterator;
}
// Sort
std::sort(Strings.begin(), Strings.end(), CMappedSorter<std::string, int>(&(Mappings)));
std::sort(Integers.begin(), Integers.end());
// Print out after sorting.
std::cout << "After Sorting" << std::endl;
std::cout << "Int\tString" << std::endl;
StringsIterator = Strings.begin();
IntegersIterator = Integers.begin();
for(unsigned int i = 0; i < ElementCount; ++i)
{
std::cout << *(IntegersIterator) << '\t' << *(StringsIterator) << std::endl;
++StringsIterator;
++IntegersIterator;
}
}
else
{
std::cout << "Error: Number of elements in each container are not equivalent." << std::endl;
}
}