Home > front end >  Single line lookup for nested std::map
Single line lookup for nested std::map

Time:10-28

Let’s say I have a std::map<int, std::map<int, std::string>>, is there a way to lookup directly for a string if you are given the two keys in a shorter statement?

Some syntax sugar for:

std::map<int, std::map<int, std::string>> nested_map;

nested_map[1][3] = "toto";

int key1 = 1;
int key2 = 3;
std::string val;
auto it1 = nested_map.find(key1);
if (it1 != nested_map.end())
{
    auto it2 = it1->second.find(key2);
    if (it2 != it1->second.end())
    {
         val = it2->second;
    }
}

Edit: I am only looking for syntax sugar to save typing a bit, because there are a lot of these nested maps in my code.

Edit2: I don’t want to throw on failure.

CodePudding user response:

What about a simple (possibly inlined) function like this:

using nested_map = std::map<int, std::map<int, std::string>>;


bool find_value(const nested_map& map, int key1, int key2, std::string& val)
{
    auto it1 = nested_map.find(key1);
    if(it1 == map.end()) return false;

    auto it2 = it1->second.find(key2);
    if(it2 == it1->second.end()) return false;
   
    val = it2->second;
    return true;
}


std::string val;
if(find_value(map, 1, 3, val))
{
    // do something useful
} 

Alternate version, which is shorter, but uses exceptions internally:

bool find_value(const nested_map& map, int key1, int key2, std::string& val)
{
    try { val = map.at(key1).at(key2); }
    catch(...) { return false; }
   
    return true;
}

CodePudding user response:

Write a recursive variadic template function that would accept map by reference and keys as variadic template argument, and returnstd::optional of innermost value type. Or may return pointer with nullptr indication that it is not found.

CodePudding user response:

Nothing wrong with creating functions to shorten your code (and remove duplication). Here is my take on that

#include <iostream>
#include <map>
#include <string>

using nested_map_t = std::map<int, std::map<int, std::string>>;

// helper struct, to be able to return 2 values from lookup function
struct lookup_t
{
    bool success = false;   // lookup was successful then this will become true
    std::string value;      // the lookup value (empty string by default)

    // implicit cast to bool, so we can use the return value in an if statement
    operator bool() const
    {
        return success;
    }
};

auto lookup_in(const nested_map_t& map, int key1, int key2)
{
    lookup_t result;

    auto it1 = map.find(key1);
    if (it1 != map.end())
    {
        auto it2 = it1->second.find(key2);
        if (it2 != it1->second.end())
        {
            result.value = it2->second;
            result.success = true;
        }
    }

    return result;
}

int main()
{
    nested_map_t nested_map;
    nested_map[1][3] = "toto";

    // syntactic sugar : bool cast of result
    if (auto result = lookup_in(nested_map, 1, 3))
    {
        std::cout << result.value << "\n";
    }
}

CodePudding user response:

With respect to "I don’t want to throw on failure." is that no exceptions at all or is a caught exception ok?

#include <map>
#include <string>
#include <iostream>
#include <exception>

std::string Get_Value(const std::map<int, std::map<int, std::string>> &in, int key1, int key2) {
    std::string res;
    try {
        res = in.at(key1).at(key2);
    }
    catch (const std::out_of_range &err) {
        res = std::string();
    }
    return res;     
}

int main(int argc, char * argv[]) {

    std::map<int, std::map<int, std::string>> nested_map;
    nested_map[1][3] = "toto";
    nested_map[1][2] = "tinman";
    nested_map[2][1] = "africa";

    auto res = Get_Value(nested_map, 1, 3);
    std::cout << res << std::endl;
    res = Get_Value(nested_map, 2, 1);
    std::cout << res << std::endl;
    res = Get_Value(nested_map, 1, 1);
    std::cout << res << std::endl;

    return 0;
}

CodePudding user response:

If you are not concerned with inserting empty strings for invalid keys, this will return that newly added string:

std::map<int, std::map<int, std::string>> nested_map;

nested_map[1][3] = "toto";

std::string val = nested_map[2][4];
  • Related