将变量与多个值进行比较的最有效方法

Most efficient way to compare a variable to multiple values?

本文关键字:比较 有效 方法 变量      更新时间:2023-10-16

在我的程序中有几次,我不得不检查一个变量是否是许多选项中的一个。例如

if (num = (<1 or 2 or 3>)) { DO STUFF }

我搞砸了'OR',但似乎没有什么是正确的。我试着

if (num == (1 || 2 || 3))

但是它什么也没做。

我想方便地区分几组。例如

if (num = (1,2,3))
else if (num = (4,5,6))
else if (num = (7,8,9))

这是c++ 11中的一个方法,使用std::initializer_list:

#include <algorithm>
#include <initializer_list>
template <typename T>
bool is_in(const T& v, std::initializer_list<T> lst)
{
    return std::find(std::begin(lst), std::end(lst), v) != std::end(lst);
}

你可以这样做:

if (is_in(num, {1, 2, 3})) { DO STUFF }

当不与内置类型一起使用时,它不是很有效。int可以正常工作,但是如果比较std::string变量,生成的代码就很糟糕了。

然而,在c++ 17中,您可以使用一个更有效的解决方案,它可以很好地处理任何类型:
template<typename First, typename ... T>
bool is_in(First &&first, T && ... t)
{
    return ((first == t) || ...);
}
// ...
// s1, s2, s3, s4 are strings.
if (is_in(s1, s2, s3, s4)) // ...

c++ 11版本在这里会非常低效,而这个版本应该会产生与手写比较相同的代码。

如果你想要检查的值足够小,你可以为你所寻找的值创建一个位掩码,然后检查该位是否被设置。

假设你关心几个组。

static const unsigned values_group_1 = (1 << 1) | (1 << 2) | (1 << 3);
static const unsigned values_group_2 = (1 << 4) | (1 << 5) | (1 << 6);
static const unsigned values_group_3 = (1 << 7) | (1 << 8) | (1 << 9);    
if ((1 << value_to_check) & values_group_1) {
  // You found a match for group 1
}
if ((1 << value_to_check) & values_group_2) {
  // You found a match for group 2
}
if ((1 << value_to_check) & values_group_3) {
  // You found a match for group 3
}

对于不超过CPU喜欢处理的自然大小的值,这种方法最有效。在现代,这通常是64,但可能根据环境的具体情况而有所不同。

您必须对每个值进行比较。例如

if (num == 1 || num == 2 || num == 3) { stuff }

你可能还想考虑切换并有意地区分大小写(尽管我不认为这是你所说的最好的解决方案)。

switch (num) {
    case 1:
    case 2:
    case 3:
        {DO STUFF}
        break;
    default:
        //do nothing.
}

我刚刚遇到了一个类似的问题,我想到了这些c++ 11解决方案:

template <class T> 
struct Is 
{ 
  T d_; 
  bool in(T a) { 
    return a == d_; 
  } 
  template <class Arg, class... Args> 
  bool in(Arg a, Args... args) { 
    return in(a) || in(args...); 
  } 
}; 
template <class T> 
Is<T> is(T d) { 
  return Is<T>{d}; 
}

或作为替代,不使用终止递归的方法。请注意,这里的比较顺序是未定义的,并且如果找到第一个匹配,也不会提前终止。但是代码更紧凑。

template <class T>
struct Is {
  const T d_;
  template <class... Args>
  bool in(Args... args) {
    bool r{ false }; 
    [&r](...){}(( (r = r || d_ == args), 1)...);
    return r;
  }
};
template <class T>
Is<T> is(T d) { 
  return Is<T>{d}; 
}

对于这两个解,代码是这样的:

if (is(num).in(1,2,3)) {
  // do whatever needs to be done
}

您可以定义一组整数,向其中添加所需的值,然后使用find方法查看所讨论的值是否在

集合中。
std::set<int> values;
// add the desired values to your set...
if (values.find(target) != values.end())
    ...

我需要为枚举做类似的事情。我有一个变量,希望对它的值范围进行测试。

这里我使用了一个可变的模板函数。注意const char*类型的专门化,这样当my_str存储"a"时,is_in( my_str, "a", "b", "c")具有预期的结果。

#include <cstring> 
template<typename T>
constexpr  bool is_in(T t, T v) {
  return t == v;
}
template<>
constexpr  bool is_in(const char* t, const char* v) {
  return std::strcmp(t,v);
}
template<typename T, typename... Args>
constexpr bool is_in(T t, T v, Args... args) {
  return  t==v || is_in(t,args...);
}

使用例子:

enum class day
{
  mon, tues, wed, thur, fri, sat, sun
};
bool is_weekend(day d)
{
  return is_in(d, day::sat, day::sun);
}

float n;
if (n<1) exit(0);  
if (n / 3 <= 1)  
   // within 1, 2, 3
else if (n / 3 <= 2)  
   // within 4, 5, 6  
else if (n / 3 <= 3)  
   // within 7, 8, 9