Search code examples
c++recursiondata-structuresstlhashmap

How to create a recursive nested hashmap in C++?


def recursiveDict():
   return collections.defaultdict(recursiveDict)

# I can create a dictionary like the following
dic = recursiveDict()
dic['a'] = 1
dic['a']['a'] = 1
dic['a']['a']['a'] = 1
dic['a']['a']['a']['a'] = 1
and so on....

I have returned to work with C++ after working for 4 years with Python and other dynamic languages. I wanted to be able to create a recursive nested list(like the one shown in the Python code above) maybe using the unordered_map or the map class.

I am unable to find a way to do that.

What I want to achieve is that the keys should be of char/string type but the value to be inserted should be of int type.

Please do let me know how can this be done.

The closest I have come to is this

struct CharMap {
    std::unordered_map<char,CharMap> map;
} root_map;

and use it like

root_map.map['a'].map['b'];

But what should I overload to get the exact syntax as above?

Thanks in advance.


Solution

  • Since you clarified that you are familiar with the basic concepts of operator overloading, I will sketch out a basic blueprint that you can follow to implement this syntax.

    Your container will implement an operator[] overload that returns a helper object. Let's say that your container is called CharMap, and after all is said and done, your container stores ints.

    class CharMap {
    
        struct key {
    
            key operator[](const std::string &);
    
            operator int();
    
            key &operator=(int n);
        };
    
    public:
    
        key operator[](const std::string &);
    
    };
    

    This would allow, for example:

    CharMap container;
    
    container["A"]["B"]["C"]=5;
    
    int n=container["D"]["E"]["F"};
    

    CharMap::operator[] returns a key helper object. That object also implements its own operator[] overload that returns another key. Finally, the key object implemets an operator= overload so you can assign to it, or operator int() overload to return a value from the container.

    It's obvious that the key would store, internally, a pointer to the CharMap's container that it came from, so that it can either update or return the appropriate value from the container. The key also keeps track of all the keys that have been used to create it, in a piecemeal fashion, internally. CharMap::key that records, internally, the first string. Then, its key::operator[] returns another key that records, internally, the original string and another one.

    Once either operator[] or operator int() gets invoked, they'll use all the accumulated strings to do their job, in some form or fashion that you'll need to figure out.

    There are also some questions of efficiency that may or may not be addressed. This approach implements your desired syntax, but depending on your situation it might require some fine tuning to optimize the underlying implementation to eliminate a bunch of internal copying and shuffling of things.

    Also, a little bit of additional work is needed to implement proper const-correctness. But all of these are just implementation details, and this is how you can implement this kind of a syntax for accessing a container that's indexed by multiple strings.