In C#, I’ve gotten spoiled over the years with LINQ and being able to create composite keys out of tuples to in-memory, static lookup tables or objects.
In a C++ project I’m working with, I needed to do something similar. However, the project’s strict requirement to keep external dependencies out was a bit of a roadblock. Boost can easily provide tuple support, but without it, a native solution had to be found. Thankfully, it just required finding the right combination of container types.
In C# 7, I’d do something like this using a value tuple as a composite key and an array of integers for the values.
// some hardcoded values for our lookup table
var list = new Dictionary<(int,int), int[]>() {
{ (1,10), new []{1,2,3} },
{ (1,11), new []{4,5,6} },
{ (1,12), new []{8,2,1} }
};
// coming in from some other source, perhaps an api lookup
var key1 = 2;
var key2 = 10;
int[] lookup = {};
list.TryGetValue((key1,key2), out lookup);
if (lookup != null) {
foreach (var val in lookup) {
// do useful things with the data, for now; print it out
Console.WriteLine(val);
}
}
Doing the same thing is possible in C++ (std:c++17) using maps, pairs, and vectors.
- maps provide us with our key/value pair container.
- pairs provide us with a two component typed object.
- vectors provide us with our dynamically sized container to hold our maps containers.
Let’s include <map>
and <vector>
in our file.
#include <map>
#include <vector>
// some hardcoded values for our lookup table
std::map<std::pair<int,int>, std::vector<int>> list = {
{{1,10}, {1,2,3}}, // { {key1, key2}, { values } }
{{1,11}, {4,5,6}},
{{1,12}, {8,2,1}}
}
// coming in from some other source, perhaps an api lookup
auto key1 = 2;
auto key2 = 10;
try {
std::vector<int> lookup = list.at({ key1, key2});
// do useful things with the data, for now; print it out.
for (const auto &val : lookup) {
std::cout << &val << "\n";
}
} catch (const std::out_of_range &ex) {
// ¯\_(ツ)_/¯
// could check length and index first, but at least this
// throws the proper error for logging, etc.
}
Once the types were sorted out, it lacks some of the syntactical sugar of C#, but codes out just the same.
Using list.at({key1,key2})
has the same complexity cost as operator[]
operations; however, rather than receiving an undefined error, we’ll receive a much safer std::out_of_range
exception if the key isn’t found.
Share this post
Twitter
Facebook
Reddit
LinkedIn
Pinterest
Email