0

I am trying to define two unordered maps at global level, I define them with loops and I don't want to put the loops to main().

More specifically I am trying to define a base-36 alphabet, I use Arabic digits for digits 0-9, then Basic Latin alphabet for digits 10-35, one map is for converting string to integer, and it should support UPPERCASE and lowercase, the other for converting integer to its string representation in given base, and it should be lowercase only.

Here is my code, obviously it doesn't work:

#include <unordered_map>

using namespace std;
const unordered_map<string, int> digits;
const unordered_map<int, string> alphabet;

for (int i = 0; i < 10; i++) {
    string d = char(i + 48);
    digits[d] = i;
    alphabet[i] = d;
}

for (int i = 10; i < 36; i++) {
    string upper = char(i + 55);
    string lower = char(i + 87);
    digits[upper] = i;
    digits[lower] = i;
    alphabet[i] = lower;
}

I am aware that if I put the loops inside the main() function, it should work. But I don't want to do that.

Is there a way to initialize them directly, and use assignment operator to define them, possibly with comprehension?

Something like the following Python code:

DIGITS = {
    **{chr(i + 48): i for i in range(10)},
    **{chr(i + j): i for i in range(10, 36) for j in (55, 87)},
}

ALPHABET = {
    **{i: chr(i + 48) for i in range(10)},
    **{i: chr(i + 87) for i in range(10, 36)},
}

Somewhat irrelevant, but here is my current working program that converts strings to numbers and vice-versa, I am trying to get rid of the if statements inside the conversion functions.

And I want to use unordered_map here to familiarize myself with it, and compare and contrast it with Python's dict.

5
  • 1
    In general I would say not. Global variables in bigger projects are a pain to deal with. But in this case you can move the initialization code to a lambda expression that will return an initialized map. Commented Aug 11, 2023 at 6:39
  • What you want to do, to use loops and computation, to initialize variables must be done in the main function. Or create a class or structure to solve the problem, and use its constructor to do the initialization. Commented Aug 11, 2023 at 6:46
  • 1
    On another note, please don't use magic numbers in the way you do. If you want to loop from '0' to '9' use those values instead. And then subtract '0' to get the actual integer value. And I recommend you make digit a map from characters to the integer value. And considering the simple arithmetic needed to convert a digit character to its integer value, or opposite, what is the maps really needed for? What is the use-case for those maps? What is the actual problem those maps are supposed to solve? Commented Aug 11, 2023 at 6:50
  • Oh and the simple arithmetic for digits is only guaranteed by the C++ specification for digits. Your upper/lower case letters are not guaranteed to work everywhere. Commented Aug 11, 2023 at 6:51
  • You use a std::string and unordered map to convert characters into numbers and vise versa? Just write a simple function with a few ifs - it will be more efficient. Maximum use a std::array to replace a couple of ifs. Commented Aug 11, 2023 at 6:54

1 Answer 1

9

Use a directly invoked lambda expression to initialize your variable.


#include <unordered_map>
#include <string>
#include <iostream>

// using namespace std; <== do not do this
const auto digits = [] 
{
    std::unordered_map<std::string, int> digits;
    for (int i = 0; i < 10; i++)
    {
        digits.insert({ std::to_string(i), i });
    }
    return digits;
}(); // make a lambda expression and immediately invoke it.

int main()
{
    // use a range-based for loop + structured binding
    // to show content of the map
    for (const auto& [key, value] : digits)
    {
        std::cout << "[" << key << ", " << value << "]\n";
    }
    return 0;
}
Sign up to request clarification or add additional context in comments.

2 Comments

He could've also written a function instead of a lambda. Same thing.
@ALX23z Probably but then the function would be available for use in the rest of the code too (this way it can only be used to initialize). This is also is quite useful for constexpr initialization (which is outside the scope of the current question).

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.