Accessing elements in maps of maps with vectors of shared pointers - c++

I have a somewhat unique situation that I can't quite get working.
I've followed a lot of examples of using maps of maps but the vector of shared pointers seems to throw me off a bit.
Suppose I have the following:
typedef boost::shared_ptr<RecCounts> RecCountsPtr;
typedef std::vector<RecCountsPtr> RecCountsPtrVec;
typedef std::map<std::string, RecCountsPtrVec> InnerActivityMap;
typedef std::map< std::string, InnerActivityMap > ActivityMap;
Where RecCounts is a simple structure.
Now, I think I've figured out how to populate my ActivityMap properly.
RecCountsPtr recCountsPtr(new RecCounts());
config.actType = "M";
config.mapDate = "2010/07";
recCountsPtr->iHousehold = "50";
recCountsPtr->iZero = "150";
config.actMap[config.actType][config.mapDate].push_back(recCountsPtr);
Yes? I don't get any compile/runtime errors for this...but since I haven't figured out how to access all the different elements of the map I can't confirm this!
This is the config structure:
struct Config
{
std::string actType;
std::string mapDate;
// Map
ActivityMap actMap;
InnerActivityMap innerActMap;
//Iterator
ActivityMap::iterator actMapIter;
InnerActivityMap::iterator innerActMapIter;
};
Now, suppose I want to access each element of the ActivityMap. How would I get the following elements?
The outer map Key?
for (config.actMapIter= config.actMap.begin();
config.actMapIter != config.actMap.end();
++config.actMapIter)
{
std::cout << "Outer Key = "
<< (*config.actMapIter).first << std::endl;
}
This seemed to do the trick.
The inner map Key?
I can't figure this out.
The inner map vector elements?
I can do it like this if I know the two keys:
config.actMap[config.actType][config.mapDate][0]->iHouehold
config.actMap[config.actType][config.mapDate][0]->iZero
...but can't seem to figure out how to iterate through them. :(
This is what I've done to try and iterate through all elements.
for (config.actMapIter= config.actMap.begin();
config.actMapIter != config.actMap.end();
++config.actMapIter)
{
std::cout << "Outer Key = " << (*config.actMapIter).first << std::endl;
for (config.innerActMapIter = config.innerActMap.begin();
config.innerActMapIter != config.innerActMap.end();
++config.innerActMapIter)
{
std::cout << "Inner Key = "
<< (*config.innerActMapIter).first << std::endl;
for (size_t i = 0;
i < config.actMap[(*config.actMapIter).first]
[(*config.innerActMapIter).first].size();
++i)
{
std::cout << "iHousehold = "
<< config.actMap[(*config.actMapIter).first]
[(*config.innerActMapIter).first]
[i]->iHousehold << std::endl;
std::cout << "iZero = "
<< config.actMap[(*config.actMapIter).first]
[(*config.innerActMapIter).first]
[i]->iZero << std::endl;
}
}
}
I don't get any errors but I only get the outer key print to the screen:
Outer Key = M
I suspect something is amiss with my inner iterator...in that it's not associated the ActivityMap. Even if I am correct I don't know how to make such an association.
Any suggestions?
ANSWER (thanks to crashmstr):
Here is a verbose version of the answer suggested by crashmstr.
for (config.actMapIter= config.actMap.begin();
config.actMapIter != config.actMap.end();
++config.actMapIter)
{
std::cout << "Outer Key = " << (*config.actMapIter).first << std::endl;
InnerActivityMap innerActMap = (*config.actMapIter).second;
InnerActivityMap::iterator innerActMapIter;
for (innerActMapIter = innerActMap.begin();
innerActMapIter != innerActMap.end();
++innerActMapIter)
{
std::cout << "Inner Key = " << (*innerActMapIter).first << std::endl;
for (size_t i = 0;
i < config.actMap[(*config.actMapIter).first][(*innerActMapIter).first].size();
++i)
{
std::cout << "iHousehold = "
<< config.actMap[(*config.actMapIter).first]
[(*innerActMapIter).first]
[i]->iHousehold << std::endl;
std::cout << "iZero = "
<< config.actMap[(*config.actMapIter).first]
[(*innerActMapIter).first]
[i]->iZero << std::endl;
}
}
}
I get the following printed to the screen:
Outer Key = M
Inner Key = 2010/07
iHousehold = 50
iZero = 150

When iterating over a map, .first is the "key", and .second is the data that belongs to that key.
So in your case:
for (config.actMapIter= config.actMap.begin();
config.actMapIter != config.actMap.end();
++config.actMapIter)
{
std::cout << "Outer Key = " << (*config.actMapIter).first << std::endl;
//(*config.actMapIter).second is a std::map<std::string, RecCountsPtrVec>
//create a new for loop to iterate over .second
}

Related

Passing the elements of a vector to a different data structure by address

I am building a 2d game and I am storing all my enemy objects in an array. Right now I am trying to implement a quadtree. Currently I am just trying to build the quadtree and am not concerned with collisions. The code that pushes items to the quadtree is the following :
for (std::vector<Enemy>::iterator i=m_enemies.begin(); i != m_enemies.end(); ++i) {
std::cout << &(*i) << "Address of the object" << std::endl;
m_quad.Insert(&(*i));
}
The code for the Insert is the following :
void Quad::Insert(sf::RectangleShape* l_gameObject){
std::cout << &l_gameObject << "dsa1" << std::endl;
std::cout << "called insert " << m_objects.size() << std::endl;
m_objects.push_back(l_gameObject);
if (m_level < m_maxLevel) {
if (m_objects.size() > 3) {
std::cout<< "creating subregions " << m_objects.size() << std::endl;
m_subRegions.push_back(Quad(m_x,m_y,m_width/2.f, m_height/2, m_level + 1, m_maxLevel-1));
m_subRegions.push_back(Quad(m_x+m_width/2.f,m_y,m_width/2.f,m_height/2.f, m_level + 1, m_maxLevel-1));
m_subRegions.push_back(Quad(m_x+m_width/2.f, m_y + m_height/2.f, m_width/2.f, m_height/2.f, m_level + 1, m_maxLevel-1));
m_subRegions.push_back(Quad(m_x, m_y + m_height/2.f, m_width/2.f, m_height/2.f, m_level + 1, m_maxLevel-1));
std::vector<int> temp;
for (int i=0; i < m_objects.size(); i++){
for (int j=0; j< m_subRegions.size(); j++) {
if (m_subRegions[j].Contains(m_objects[i])) {
m_subRegions[j].Insert(m_objects[i]);
temp.push_back(i);
break;
}
}
}
for (int i = temp.size(); i > -1; i--){
m_objects.erase(m_objects.begin() + temp[i]);
}
}
}
}
When I print the address that I am passing to the Insert function and the one I have in the function I see that they are different. In fact the on in is always the same and the one I pass is always different as it should be. Could anyone clarify why that is the case ?
EDIT : Thanks to gsamaras for pointing out that I was printing the address of the parameter.
Followup question
When I use the methods of the object I am addressing in the first for loop I get the correct results, but when I do the same thing in the Insert function I get 0. Why is that ?
You are printing the address of the address.
Change this:
std::cout << &l_gameObject << "dsa1" << std::endl;
to this:
std::cout << l_gameObject << "dsa1" << std::endl;
in order to print the same thing as outside your of your function.
Inside Insert, you're printing the address of the parameter.
Outside Insert, you're printing the parameter's value.
You want
std::cout << l_gameObject << "dsa1" << std::endl;
since l_gameObject is the address you're passing in.

Processing array of generic BSON documents with MongoDB C++ driver

I have the following document in my MongoDB test database:
> db.a.find().pretty()
{
"_id" : ObjectId("5113d680732fb764c4464fdf"),
"x" : [
{
"a" : 1,
"b" : 2
},
{
"a" : 3,
"b" : 4
}
]
}
I'm trying to access and process the elements in the "x" array. However, it seems that the Mongo driver is identifying it not as an array of JSON document, but as Date type, as shown in the following code:
auto_ptr<DBClientCursor> cursor = c.query("test.a", BSONObj());
while (cursor->more()) {
BSONObj r = cursor->next();
cout << r.toString() << std::endl;
}
which output is:
{ _id: ObjectId('51138456732fb764c4464fde'), x: new Date(1360233558334) }
I'm trying to follow the documentation in http://api.mongodb.org/cplusplus and http://docs.mongodb.org/ecosystem/drivers/cpp-bson-array-examples/, but it is quite poor. I have found other examples of processing arrays, but always with simple types (e.g. array of integer), but not when the elements in the array are BSON documents themselves.
Do you have some code example of procesing arrays which elements are generic BSON elements, please?
you could use the .Array() method or the getFieldDotted() method: as in the following:
Query query = Query();
auto_ptr<DBClientCursor> cursor = myConn.query("test.a", query);
while( cursor->more() ) {
BSONObj nextObject = cursor->next();
cout << nextObject["x"].Array()[0]["a"] << endl;
cout << nextObject.getFieldDotted("x.0.a") << endl;
}
At the end, it seems that embeddedObject() method was the key:
auto_ptr<DBClientCursor> cursor = c.query("test.a", BSONObj());
while (cursor->more()) {
BSONObj r = cursor->next();
cout << "Processing JSON document: " << r.toString() << std::endl;
std::vector<BSONElement> be = r.getField("x").Array();
for (unsigned int i = 0; i<be.size(); i++) {
cout << "Processing array element: " << be[i].toString() << std::endl;
cout << " of type: " << be[i].type() << std::endl;
BSONObj bo = be[i].embeddedObject();
cout << "Processing a field: " << bo.getField("a").toString() << std::endl;
cout << "Processing b field: " << bo.getField("b").toString() << std::endl;
}
}
I was wrongly retrieving a different ObjectID and a different type (Date instead of array) becuase I was looking to a different collection :$
Sorry for the noise. I hope that the fragment above helps others to figure out how to manipulate arrays using the MongoDB C++ driver.

C++ Structs in arrays

Am i doing this right, I want a map with a Integer as key, and struct as value. What is the easiest way to, say I want the object at 1. How do I retrieve the value of isIncluded? The last two lines in the code, I tried doing it, but then I realized I donĀ“t really know what is the way to retrieving values of structs in a numbered Map array.
Do I need to call cells.get(1) and assign that to a new temporarely struct to get its values?
/** set ups cells map. with initial state of all cells and their info*/
void setExcludedCells (int dimension)
{
// Sets initial state for cells
cellInfo getCellInfo;
getCellInfo.isIncluded = false;
getCellInfo.north = 0;
getCellInfo.south = 0;
getCellInfo.west = 0;
getCellInfo.east = 0;
for (int i = 1; i <= (pow(dimension, 2)); i++)
{
cells.put(i, getCellInfo);
}
cout << "Cells map initialized. Set [" << + cells.size() << "] cells to excluded: " << endl;
cells.get(getCellInfo.isIncluded);
cells.get(1);
}
the Map, is declared as an private instance variable like this:
struct cellInfo {
bool isIncluded;
int north; // If value is 0, that direction is not applicable (border of grid).
int south;
int west;
int east;
};
Map<int, cellInfo> cells; // Keeps track over included /excluded cells
From the documentation for Map, it appears that .get() returns a ValueType.
You would use it thus:
// Display item #1
std::cout << cells.get(1).isIncluded << "\n";
std::cout << cells.get(1).north << "\n";
Or, since the lookup is relatively expensive, you could copy it to a local variable:
// Display item #1 via initialized local variable
cellInfo ci = cells.get(1);
std::cout << ci.isIncluded << " " << ci.north << "\n";
// Display item #2 via assigned-to local variable
ci = cells.get(2);
std::cout << ci.isIncluded << " " << ci.north << "\n";
My best advice is to use the standard library's std::map data structure instead:
// Expensive way with multiple lookups:
std::cout << cells[1].isIncluded << " " << cells[1].north << "\n";
// Cheap way with one lookup and no copies
const cellinfo& ci(maps[1]);
std::cout << ci.isIncluded << " " << ci.north << "\n";

Boost:: Dijkstra Shortest Path, how to get vertice index from path iterator?

Before you start reading, to help you understand my issue, I am telling that I have copied the code from this link: Dijkstra Shortest Path with VertexList = ListS in boost graph
So.. I am rewriting my program code to use boost, but now when 99% is ready I am stuck with my GPS (for a game).
I have a list of nodes, which I added in a way which fortunately was easy to convert to the boost method. The thing I needed to do was just create a vertice variable like this:
Vertex Vx[MAX_NODES];
I copied the typedefs from the link I have given.
The way I add vertices is this:
stringstream s;
s << i;
Vx[i] = add_vertex(s.str(),dgraph);
Where "i" equals an integer number. (eg int i = 9)
And eges are also easy to add. Now, I have my own structured array called "xNode". and eg :
xNode[i] holds all the information for X Y Z positions (xNode[i].X xNode[i].Y etc) of the nodes.
Now when using the code snippet from the link I have done this:
// Write shortest path
std::cout << "Shortest path from " << startid << " to " << endid << ":" << std::endl;
float totalDistance = 0;
for(PathType::reverse_iterator pathIterator = path.rbegin(); pathIterator != path.rend(); ++pathIterator)
{
std::cout << source(*pathIterator, dgraph) << " -> " << target(*pathIterator, dgraph)
<< " = " << get( boost::edge_weight, dgraph, *pathIterator ) << std::endl;
}
And this is where I am stuck, as "source(*pathIterator, dgraph)" and "target(*pathIterator, dgraph)
" Get addresses, but I need the vertice indexes to access xNode[i], i is the NodeID (or well the vertice ID | Vx[i]).
How can I do that?
EDIT:
I tried to do:
for(PathType::reverse_iterator pathIterator = path.rbegin(); pathIterator != path.rend(); ++pathIterator)
{
for(int i = 0; i < MAX_NODES; ++i)
{
if(source(*pathIterator, dgraph) == *((Vertex*)Vx[i]))
{
cout << " " << i << " " << endl;
break;
}
}
}
but this just crashes..
With the typedefs from that question, you can use get(boost::vertex_index, dgraph, v) to get the index of v. You can also cache the property map using:
IndexMap vi = get(boost::vertex_index, dgraph);
then use get(vi, v) to get the index for v.

C++ STL map with custom comparator storing null pointers

I'm trying to write a copy constructor for an object managing a STL map containing pointers, where the key is a string. However, when I attempt to insert new values in the map, the pointers are set to NULL:
// ...
for(std::map<std::string, data_base*, order>::const_iterator it = other.elements.begin();
it != other.elements.end(); ++it){
data_base *t = it->second->clone();
std::cout << "CLONE: " << std::hex << t << std::endl;
elements[it->first] = t;
std::cout << "INSERTED: " << std::hex << elements[it->first] << std::endl;
}
// ...
other is the object being copied and elements the map. The clone() method returns a pointer to a new object (via new).
Running the code above I get something like:
CLONE: 0xcfbbc0
INSERTED: 0
I'm not a very experienced programmer and this issue is probably simple to fix, but I didnt find any solution to it searching around.
Thanks a lot for your time.
I don't see any problem with this code, other than maybe
std::map<std::string, data_base*, order>::const_iterator it
Here order gives the key comparator to use to sort the pairs contained in the map (often implemented as a tree).
Maybe you're doing something wrong in it, making your [] operator don't find the right ke, making your last line logging a new pair with a null ptr.
First, try without that order, using the default key-comparator (std::less), then if it don't work, post your order definition and the map declaration. If it's not enough, just provide a simple complete program that reproduce the problem.
I just wrote a simple similar test, using the default key-comparator :
#include <map>
#include <string>
#include <iostream>
struct Data
{
int k;
Data* clone() { return new Data(); }
};
typedef std::map< std::string, Data* > DataMap;
DataMap data_map;
int main()
{
data_map[ "hello" ] = new Data();
data_map[ "world" ] = new Data();
DataMap other_map;
for( DataMap::const_iterator it = data_map.begin(); it != data_map.end(); ++it)
{
Data*t = it->second->clone();
std::cout << "CLONE: " << std::hex << t << std::endl;
other_map[it->first] = t;
std::cout << "INSERTED: " << std::hex << other_map[it->first] << std::endl;
}
std::cin.ignore();
return 0;
}
On VS2010SP1, this outputs :
CLONE: 00034DD0
INSERTED: 00034DD0
CLONE: 00035098
INSERTED: 00035098
So it should be the problem, or maybe you're doing something wrong before.
Try this out, to help debug the issue. I'd recommend double-checking that the order function is correct. You can remove it to use std::less<T>, which is known to work.
// ...
typedef std::map<std::string, data_base*, order> string_db_map;
for(string_db_map::const_iterator it = other.elements.begin();
it != other.elements.end();
++it)
{
data_base *t = it->second->clone();
std::cout << "CLONE: " << std::hex << t << std::endl;
std::pair<string_db_map::iterator, bool) result = elements.insert(
string_db_map::value_type( it->first, t));
if ( !result.second )
{
std::cout << "element['" << it->first << "'] was already present, and replaced." << std::endl;
}
std::coud << "INSERTED [iterator]: " << std::hex << (*result.first).second << std::endl;
std::cout << "INSERTED [indexed]: " << std::hex << elements[it->first] << std::endl;
}
// ...