tags:

views:

134

answers:

3

I was wondering if it was possible to create a struct containing a number of variables and a map in a map.

What I have at the moment:

typedef std::map<std::string,double> lawVariables;  

struct ObjectCustomData {   
  std::string objectType;    
  bool global_lock;   
  std::map<std::string, lawVariables> lawData;   
 };

This struct is then passed on to another function as a single data block for that object.

The structure setup is as follows: Each object has a data block that contains: its ObjectType, a bool for a lock, and a varying number of "laws" that could look like this:

law1 -> var_a = 39.3;
     -> var_g = 8.1;
law8 -> var_r = 83.1;
     -> var_y = 913.3;
     -> var_a = 9.81;

Firstly, I'm unsure whether I should be using a Map within a Map and secondly even if this would be valid, I'm unsure how to fill it with data and how to recall it afterwards. I looked at maps because then I can search (on a name) if a certain object has a certain law, and if that law has certain variables.

(sorry for the first messy post appearance, hope this is better :) )

+2  A: 

I was wondering if it was possible to create a struct containing a number of variables and a map in a map

Yes. It is possible to have Map as value inside another map.

If you are particular about the order of insertion and the entries are less for inner map then your data structure can looks like:

typedef std::vector<std::pair<std::string,double> > lawVariables;  

struct ObjectCustomData {   
  std::string objectType;    
  bool global_lock;   
  std::map<std::string, lawVariables> lawData;   
 };

EDIT: I saw your edit now. If lookup is your primary requirement then go for map.

Example:

 typedef std::map<std::string,double> lawVariables;  

    struct ObjectCustomData {   
      std::string objectType;    
      bool global_lock;   
      std::map<std::string, lawVariables> lawData;   
     };

void test(ObjectCustomData& data)
{
  lawVariables& variable = data.lawData["law_1"];
  variable["var_a"] = 39.3;

}
aJ
@aJ - When I try to compile your test method, I get "error: no match for 'operator[]' in 'data["law_1"]'. Does it compile for you? I'm using g++ compiler in cygwin.
dcp
sorry. The first line should have been data.lawData["law_1"]; pls refer my edit.
aJ
Thanks a ton for the answers, both of you! :D
Karrok
+1  A: 

What you have should work. You can load the data like this:

  ObjectCustomData data;
  data.lawData["law_1"]["var_a"] = 39.3;
  data.lawData["law_1"]["var_g"] = 8.1;
  data.lawData["law_8"]["var_r"] = 83.1;
  .
  .
  .

You can check for existence of elements like this:

  if (!data.lawData.count("law_x")) {
    cout<<"law_x not found"<<endl;
  }

  if (data.lawData.count("law_1")) {
    cout<<"law_1 was found"<<endl;
  }
dcp
The code for checking existence of elements is bad code. Don't do that.If "law_x" key doesn't exist, you create it (create a blank map), then query it's size. This means allocation for the string, constructing the map and so on.You're better off using std::map::find.
utnapistim
@utnapistim - Good point, thank you for your comment. I actually prefer using count instead of find since it's a little cleaner IMO. I've updated my answer.
dcp
A: 

Just adding the following incase someone else might be looking for it aswell: (note, some of it might go unused or so, feel free to let me know! :))

in .h:

typedef std::map<std::string,double> lawVariables;
typedef std::map<std::string,double>::iterator lawVars;
struct ObjectCustomData {
    std::string objectType;
    bool global_lock;
    std::map<std::string, lawVariables> lawData;
};


template <typename K, typename V, class C, class A>
std::ostream &operator<< (std::ostream &os, std::map<K,V,C,A> const& m)
{
    os << "{ ";
    typename std::map<K,V,C,A>::const_iterator p;
    for (p = m.begin(); p != m.end(); ++p) {
        os << p->first << ":" << p->second << ", ";
    }
    return os << "}";
}

Note: the template stuff is so you can simply cout an entire map-in-map.

    void setCustomData();
    void showCustomData();
    bool checkLaw(std::string law);
    bool checkVar(std::string law,std::string var);
    double getLawVar(std::string law, std::string var);
    template<class T,class A>
    void showMap(const std::map<T, A>& v);
    ObjectCustomData ocd;

note: The setCustomData will just fills the map-in-map with some random data for testing purpose, showCustomData just uses the template and custom operator to show the entire map. checkLaw and checkVar make sure a certain value even exists and getLawVar returns the value of a certain val of a certain law. showMap shows the entire content of the map-in-map with a somewhat nicer output.

in the .cpp:

Ill skip the setCustomData, it's just a bunch of ocd.lawData[law][var] = 123.45;

    void showCustomData() {
        std::cout <<ocd.lawData<<std::endl; 
    }
    bool checkLaw(std::string law){
        if ((int)ocd.lawData[law].size() != 0) {
            return true;
        }
        else {
            return false;
        }   
    }
    bool checkVar(std::string law, std::string var){        
        lawVars lVars = ocd.lawData[law].find(var);
        if(lVars != ocd.lawData[law].end()){
            return true;
        }
        else {
            return false;
        }
    }
    double getLawVar(std::string law, std::string var){
        if (checkLaw(law) && checkVar(law, var)){
            return ocd.lawData[law].find(var)->second;
        }
        else {return 0.0;}
    }
    template<class T, class A>
    void showMap(const std::map<T, A>& v) {
        for (std::map<T, A>::const_iterator ci = v.begin(); ci != v.end(); ++ci) {
            std::cout << ci->first <<" -> ";
            lawVariables tmpLaw = ci->second;
            lawVars lVars;
            for (lVars = tmpLaw.begin(); lVars != tmpLaw.end(); lVars++){
                std::cout << lVars->first << " : " << lVars->second <<"\t";
            }
            std::cout<<std::endl;
        }
        std::cout<<std::endl;
    }

Hope this is atleast somewhat usefull for someone, feel free to comment on stuff I could/should do better.

Karrok
Please note that all the strings and maps that are being passed by value in this code should be passed as const references. Also, you need to investigate the concept of the const member function.
anon
Years of Java :< thanks, I keep forgetting to properly use references and pointers :/
Karrok