2016-05-25 4 views
0

Мне нужен способ присвоения чисел буквам на C++, например, '$' будет представлять номер 1. Очевидно, мне нужно иметь возможность получить номер от символа с чем-то вроде функции, например. getNumFromChar('$') вернется 1 и getNumFromChar('#') вернет 2. Есть ли простой и быстрый способ сделать это на C++?Назначение чисел символам C++

+0

Вы можете использовать [ 'станд :: map'] (http://en.cppreference.com/w/cpp/container/map) –

+4

['char'acters ** are ** numbers] (http://www.asciitable.com/) – Drop

+0

'' $ "' и '" # "' не являются символами, это строки (строковые литералы, если быть точным) – Drop

ответ

2

Создать вектор std::vector<int> v(256,0); который индексируется вашими персонажами и изначально все их числа равны нулю, что можно трактовать как недопустимые номера. Наконец, назначьте для каждого «нумерованного» символа некоторое число, например. v['$'] = 1; v['#'] = 2; используя тот факт, что символы фактически являются целыми числами от 0 до 255.

5

Самый быстрый способ - написать таблицу поиска записей 256, содержащую отображаемые значения в индексе ASCII символа. Это подобно тому, как isdigit и tolower работы, например:

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

    return table[c & 0xff]; 
} 
+0

Возможно, вы захотите сделать таблицу static/constexpr. – MikeMB

1

Как было отмечено в комментариях, вы можете использовать std::map следующим образом:

#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; 
} 

Живая демо here.

Большинство других ответов будут работать только в том случае, если вы сохранили максимум 256 значений. Однако, используя Maps, вы можете хранить только любое количество элементов.

+0

И если вы знаете, что ваше ключевое пространство занимает не более 256 записей, карта, вероятно, является самым медленным возможным решением. – MikeMB

+0

@MikeMB, я согласен, но я считаю, что поиск по карте был бы предпочтительнее для поиска в векторе (как это предложил Михаил Вольский выше). И основой моей веры является [это] (http://stackoverflow.com/questions/6985572/which-is-the-fastest-stl-container-for-find). OP не использует 'std :: find' как таковой, но он все равно * смотрит вверх. И кроме того, ОП нигде не упоминает, что он работает только с 256 значениями. –

+0

'std :: find' и индексированный поиск - это две полностью несвязанные операции . 'std :: find' всегда O (n), тогда как индексированный поиск базы для массивов и векторов - это постоянное время (и на самом деле сводится к чему-то. как 1-3 инструкции). Что еще более важно, 'std :: map' является кэшированием и конвейерным кошмаром, и (на современных процессорах) это часто имеет более высокое влияние производительности, чем алгоритмическая сложность. Если вы заинтересованы в выполнении операций с различными структурами данных, я могу рекомендовать [этот разговор] (https://www.youtube.com/watch?v=fHNmRkzxHWs) как отправную точку . – MikeMB

0

Многих людей предполагает std::map<char,int>, что это хорошо и работает, но быстрее (?) Способом сделать это без каких-либо зависимостей является просто использовать массивное заявление, переключатель

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

В зависимости от того, насколько вы заботитесь о производительности/использовании памяти и о том, сколько случаев вы должны будете писать, это может быть или не быть жизнеспособным способом делать то, что вы хотите. Просто подумал, что я брошу его там, так как на момент написания этой статьи я не верю, что кто-то есть.

EDIT: Кроме того, в зависимости от частоты использования каждого отдельного символа, и если вы знаете все сопоставление перед использованием этой функции или если вы когда-либо меняете отображение, то std::map будет лучше, но я считаю, что это быстрее в противном случае.

3

Если вы хотите сами присвоить значения, используйте карту и сохраните свой ключ в комбинациях букв. Если вы в порядке с заранее заданными уникальными значениями, сопоставленными каждой букве, и используете только символы ASCII, тогда введите их в целые числа ... ex) std :: static_cast < int> ('$');

0

Вы могли бы сделать что-то вроде этого:

#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; 
} 

я обращался к uninitizialized ключ, бросая исключение, но вы могли бы сделать это разными способами.

0

Если ваша поддержка компилятора C++ 11, вы можете использовать std::unordered_map в качестве контейнера для хранения символа и double, как std::unordered_map<char,double>. Unordered map - ассоциативный контейнер, содержащий пары ключ-значение с уникальными ключами. Поиск, вставка и удаление элементов имеют среднюю постоянную сложность. В вашей проблеме символ - это ключ, а double - ваше значение, char-double должен быть ключ-значением, хранящимся в контейнере.

0

Есть уже много разумных ответов ...Я предпочитаю static_cast<int>('#')

И всегда должно быть самое глупое бесполезное представление шаблона времени компиляции о том, как решить проблему.

Я знаю, что это глупо, и я плохо разбираюсь в таких вещах, но вот мой выстрел в него в C++ 11. Не воспринимай меня всерьез. Мне просто нужно было сделать что-то немое.

#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; 
} 

Я думаю, что вы можете сделать GetInt() constexpr тоже в C++ 14, но я могу ошибаться и не может проверить это прямо сейчас.

Конечно, это действительно бесполезно, так как вы должны знать письмо во время компиляции, но вы могли бы работать вокруг этого путем, ну, просто не делает GetInt шаблонной функции ...