Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Efficient way to compare more 50 strings

Tags:

c++

string

c++11

I have method which takes two parameters one as string and other as int.

The string has to compare with more than 50 string and Once the match is found int value need to be mapped with hard coded string as Example below

EX:

  string Compare_Method(std::string str, int val) {

     if(str == "FIRST")
{
  std::array<std::string, 3> real_value = {"Hello1","hai1","bye1"}
  return real_value[val];
}

     else if(str == "SECOND")
{
  std::array<std::string, 4> real_value = {"Hello2","hai2","bye2"}
  return real_value[val];
}

     else if(str == "THIRD")
{
  std::array<std::string, 5> real_value = {"Hello3","hai3","bye3"}
  return real_value[val];
}

//----- 50+ else if

}

My approach is as above. What will be the efficient way

1.To compare more than 50 string.

2. create std::array for each if case

EDITED : std::array size is not fixed it can be 3,4,5 as edited above.

like image 330
rim Avatar asked Dec 04 '19 13:12

rim


People also ask

How can I speed up my string comparison?

So, Use 'is' (identity) operator than '==' (equality) operator to speed up your heavy string comparison operations.

Is Strcmp fast?

While comparing the two function, in a loop repeted 500'000'000 times, strcmp execute too much fast, about x750 times faster. The execution time of that function is 3.058s , while strcmp only 0.004s .


3 Answers

This would be my way of doing that. The data structure is created only once and the access times should be fast enough

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

std::string Compare_Method(const std::string& str, int val)
{
    //                                  or std::vector<std::string>
    static std::unordered_map<std::string, std::array<std::string, 3>> map
    {
        {  "FIRST", { "Hello1", "hail1", "bye1" }},
        { "SECOND", { "Hello2", "hail2", "bye2" }},
        {  "THIRD", { "Hello3", "hail3", "bye3" }},
        // 50+ more
    };

    // maybe check if str is present in the map

    return map[str][val];
}

int main()
{
    std::cout << Compare_Method("SECOND", 1) << std::endl;
}

If std::unordered_map isn't (fast) enough for you, you can come up with some sort of static optimal hash structure, since keys are known at compile time.

like image 167
Zereges Avatar answered Oct 17 '22 15:10

Zereges


If those 50 strings are something you will be widely using throughout your program, string comparisons will take a toll on performance. I'd suggest you to adapt them to an enum.

enum Strings
{
    FIRST,
    SECOND,
    THIRD,
    …
    …
}

You'll obviously need a method to convert string to int whenever you get one from the source (user input, file read, etc.). This should be as infrequent as possible since your system now works on enum values (which can be used as indices on STL containers as we see in the next step)

int GetEnumIndex(const std::string& str)
{
    // here you can map all variants of the same string to the same number
    if ("FIRST" == str || "first" == str) return 1;
    …
}

Then, the comparison method can be based on the enum instead of the string:

std::string Compare_Method(const int& strIndex, int val)
{
    static std::vector<std::vector<std::string>> stringArray
    {
        { "Hello1", "hail1", "bye1" },
        { "Hello2", "hail2", "bye2", "aloha2" },
        { "Hello3", "hail3", "bye3", "aloha3", "tata3" },
        …
    };
    return stringArray[strIndex][val];
}
like image 37
CinCout Avatar answered Oct 17 '22 15:10

CinCout


With information provided by you, I tried various variations to find out best way to achieve objective. I am listing best one here. You can see other methods here.

You can compile it and run run.sh to compare performance of all cases.

std::string Method6(const std::string &str, int val) {
  static std::array<std::string, 5> NUMBERS{"FIRST", "SECOND", "THIRD",
                                            "FOURTH", "FIFTH"};
  static std::array<std::vector<std::string>, 5> VALUES{
      std::vector<std::string>{"FIRST", "hai1", "bye1"},
      std::vector<std::string>{"Hello1", "SECOND", "bye1"},
      std::vector<std::string>{"Hello1", "hai1", "THIRD"},
      std::vector<std::string>{"FOURTH", "hai1", "bye1"},
      std::vector<std::string>{"Hello1", "FIFTH", "bye1"}};
  for (int i = 0; i < NUMBERS.size(); ++i) {
    if (NUMBERS[i] == str) {
      return VALUES[i][val];
    }
  }
  return "";
}

For simplicity I have been using NUMBERS with length of 5 but you can use what ever length you want to.

VALUES is std::array of std::vector so you can add any number if element to std::vector.

output from github code.

Method1   880
Method2   851
Method3   7292
Method4   989
Method5   598
Method6   440

You output may be different based on you system and system load at the time of execution.

like image 2
Manthan Tilva Avatar answered Oct 17 '22 15:10

Manthan Tilva