【问题标题】:Efficient way to compare more 50 strings比较更多 50 个字符串的有效方法
【发布时间】:2019-12-04 13:59:03
【问题描述】:

我的方法采用两个参数,一个为string,另一个为int

字符串必须与超过 50 个字符串 进行比较,一旦找到匹配,int 值需要用硬编码字符串映射,如下例所示

前:

  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

}

我的方法如上。什么是有效的方法

1.比较50多个字符串。

2。为每个 if 情况创建 std::array

已编辑:std::array 大小不固定,可以是 3、4、5,如上编辑。

【问题讨论】:

  • 将您的字符串和字符串数组存储在unordered_map 中。这将更有效率。您还可以形成由字符串和值组成的复合键,并使用该键来索引地图。
  • sn-p 中显示的字符串是示例还是实际预期值?
  • @rim 在您的所有else if 中,您还使real_value 的数组更大,但您不会向数组中添加更多字符串。以防万一你不知道:)
  • 只是一个想法:也许可以考虑使用SMID 的方法。不确定这在 C++ 中的实际效果如何,对于字符串操作,它也可能看起来很丑。

标签: c++ string c++11


【解决方案1】:

这将是我这样做的方式。数据结构只创建一次,访问时间应该足够快

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

如果std::unordered_map 对您来说不够(快),您可以想出某种静态最佳哈希结构,因为键在编译时是已知的。

【讨论】:

  • 您还可以为 std::unordered_map 制作自定义散列函数以使其更快,因为键是已知的
  • 在 unordered_map 上使用 at() 或运算符 [] 是有风险的游戏,好像传递给函数的第一个参数在 unordered_map 中不存在,那么您必须面对 out_of_bound 异常。最好使用 find()。
  • @Romen 我考虑到了这些。请注意我的代码中的 cmets。
  • @Mannoj 是的,这就是为什么有 maybe check if str is present in the map 的评论。如果 OP 将确保不使用无效参数调用 Compare_Method,则不需要 find
  • 我个人的偏好是无论如何都使用find,以避免在调用map[str] 时让operator[] 使用的代码插入密钥和默认值,并且可能会影响创建默认值的性能如果找不到 str 要插入的值。
【解决方案2】:

如果您将在整个程序中广泛使用这 50 个字符串,string 比较将影响性能。我建议您将它们调整为 enum

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

您显然需要一种方法将string 转换为int,只要您从源(用户输入、文件读取等)获得一个。这应该尽可能不频繁,因为您的系统现在可以处理枚举值(可以用作 STL 容器上的索引,我们将在下一步中看到)

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

那么,比较方法可以基于enum而不是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];
}

【讨论】:

  • 您显然需要一种将string 转换为int 的方法,因此您的GetEnumIndex 也会执行大量比较。
  • 您说“字符串比较会影响性能”,但 GetEnumIndex 仍然进行字符串比较?
【解决方案3】:

根据您提供的信息,我尝试了各种变化来找出实现目标的最佳方法。我在这里列出了最好的一个。其他方法可以看here

您可以编译它并运行run.sh 来比较所有情况的性能。

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

为简单起见,我一直使用长度为 5 的 NUMBERS,但您可以使用任何您想要的长度。

VALUESstd::arraystd::vector,因此您可以将任何数字 if 元素添加到 std::vector

来自 github 代码的输出。

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

根据执行时的系统和系统负载,您的输出可能会有所不同。

【讨论】:

  • 链接无效
  • @rim 立即查看。
  • 接受这一点,因为我找到了更多信息和最佳方法
  • 您的其他方法都没有使用std::unordered_map,它可以比std::map 更快地进行查找。我将测试该地图结构的变体并将其包含在内以确保答案的完整性。 (它甚至可能比您为答案选择的方法更快?)
  • 您的测试方法似乎也有偏差,Method6 只需执行最多 5 次字符串比较,因为您为 NUMBERS 选择了如此小的大小。最初的问题表明NUMBERS 实际上至少 50 个元素长,这将导致更有效的查找结构,如std::mapstd::unordered_map,以更好地展示它们的性能。我进行了自己的测试,发现std::unordered_map 比线性搜索std::array 快 10 到 10000 倍(取决于键在数组中的位置,也在 MSVC 而不是 GCC 上)。
猜你喜欢
  • 2011-03-22
  • 2021-06-01
  • 2010-12-09
  • 1970-01-01
  • 2012-05-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多