Mashpoe
Mashpoe

Reputation: 524

Assign numbers to characters C++

I need a way to assign numbers to letters in C++, for example, '$' would represent the number 1. I obviously need to be able to obtain the number from the character with something like a function, e.g. getNumFromChar('$') would return 1 and getNumFromChar('#') would return 2. Is there an easy and fast way to do this in C++?

Upvotes: 1

Views: 8716

Answers (8)

owacoder
owacoder

Reputation: 4873

The fastest way is to write a 256 entry lookup table, containing the mapped values in the character's ASCII index. This is similar to how isdigit and tolower work, for example:

int getNumFromChar(char c)
{
    static const int table[256] = {/* table entries */};

    return table[c & 0xff];
}

Upvotes: 6

vianney
vianney

Reputation: 161

There are already a lot of reasonable answers... I prefer the static_cast<int>('#')

And there always has to be the most stupid useless compile time template idea about how to solve a problem.

I know it's stupid, and I'm not good at this kind of things, but here is my shot at it in c++11. Don't take me seriously. I just had to do something dumb.

#include <string>
#include <array>
#include <utility>
#include <iostream>

constexpr uint  kNbChars {3};

constexpr std::array<std::pair<char, int>, kNbChars> kCharToInt {
      std::make_pair('$', 1)
    , std::make_pair('#', 2)
    , std::make_pair('@', 3)
};

template <char c>
int getInt()
{
    for (auto pair : kCharToInt)
    {
        if (pair.first == c)
        { return pair.second; }
    }
    return -1;
}

int     main()
{
    std::cout << getInt<'#'>() << std::endl;
    std::cout << getInt<'g'>() << std::endl;
}

I think you can make getInt() constexpr too in c++14, but I may be wrong and cannot check it right now.

Of course it really is useless since you have to know the letter at compile time, but you could work around that by, well, just not making getInt a template function...

Upvotes: 0

TongChen
TongChen

Reputation: 1430

If your compiler support c++11 feature,you can use std::unordered_map as container to store char and double like std::unordered_map<char,double>. Unordered map is an associative container that contains key-value pairs with unique keys. Search, insertion, and removal of elements have average constant-time complexity.In your problem char is the key and double is your value,char-double must be the key-value stored in container.

Upvotes: 0

Sagar Patel
Sagar Patel

Reputation: 61

If you would like to assign the values yourself use a map and store your key to letter combinations. If you are ok with preassigned unique values mapped to each letter, and are only using ASCII characters, then type cast them to integers... ex) std::static_cast< int >('$');

Upvotes: 3

vincent
vincent

Reputation: 1390

You could do something like this:

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

typedef std::map<char, int> easymap_type;

class EasyMap {
public:
    EasyMap() {}
    virtual ~EasyMap() {}

    void assign_int_to_char(const int& i, const char& c)
    {
        _map[c] = i;
    }

    int get_int_from_char(const char& c) const
    {
        easymap_type::const_iterator it = _map.find(c);
        if (it == _map.end())
        {
            std::cerr << "EasyMap Error: uninitialized key - '" << c << "'" << std::endl;
            throw std::exception();
        }
        return it->second;
    }

private:
    easymap_type _map;
};

int main()
{

    EasyMap ezmap;

    ezmap.assign_int_to_char(42, 'a');

    std::cout << "EasyMap[a] = " << ezmap.get_int_from_char('a') << std::endl;
    std::cout << "EasyMap[b] = " << ezmap.get_int_from_char('b') << std::endl;

    return 0;
}

I handled an uninitizialized key by throwing an exception, but you could do it different ways.

Upvotes: 0

ocket8888
ocket8888

Reputation: 1140

A lot of people are suggesting std::map<char,int>, which is fine and works, but a faster (?) way of doing this with no dependencies is to just use a massive switch statement

int getNumFromChar(char c){
    switch(c){
        case '$':
            return 1;
        case '#':
            return 2;
        //etc
    }
    return -1; //just in case of error, for style points
}

Depending on how much you care about performance/memory usage and how many case statements you'd have to write, this may or may not be a viable way to do what you want. Just thought I'd throw it out there since at the time of this writing I don't believe anyone has.

EDIT: Also, depending on the frequency of use of each individual character, and if you know the entire mapping before using this function or if you ever change the mapping, a std::map is way better, but I believe this is faster otherwise.

Upvotes: 0

abhishek_naik
abhishek_naik

Reputation: 1297

As pointed out in the comments, you can use a std::map in the following way:

#include <iostream>
#include <map>
#include <cstring>

struct myComp
{
    bool operator()(const char* s1, const char* s2) const
    {
    return strcmp(s1, s2) < 0;
    }
};

int main()
{
    std::map<const char*, int, myComp> test;

    test["$"] = 1;
    test["#"] = 2;

    std::cout << "$ -> " << test["$"] <<"\n";
    std::cout << "# -> " << test["#"] <<"\n";

    return 0;
}

Live demo here.

Majority of the other answers will work only if you have a maximum of 256 values to be stored. However, using Maps, you can store just any number of elements.

Upvotes: 1

Mikhail Volskiy
Mikhail Volskiy

Reputation: 209

Create a vector std::vector<int> v(256,0); which is indexed by your characters and initially all of their numbers are zeros that you could treat as invalid numbers. Finally assign for each 'numbered' character some number e.g. v['$'] = 1; v['#'] = 2; using a fact that characters are actually integers from 0 to 255.

Upvotes: 2

Related Questions