有效比较整数列表与C++中给定的整数

efficient comparison of list of ints with a given int in C++

本文关键字:整数 比较 列表 有效 C++      更新时间:2023-10-16

有没有一种高效/优雅的方法来比较整数列表与C++中给定的整数。假设我有一个四重数字:P、Q、R、S,我需要将它们与给定的 int T 进行比较以获得不同的案例场景。

if (P == T && Q != T && R != T && S != T) case('P'); else if (P != T && Q == T && R != T && S != T) case('Q'); else if (P != T && Q != T && R == T && S != T) case('R'); else if (P != T && Q != T && R != T && S == T) case('S');

同样,我将有 6 个配对案例:PQ、QR、PR ...、4 个三重案例和 1 个四重案例。如您所见,很多明确的比较!有没有一种优雅的方法可以使用 STL 容器来做到这一点?

我需要以下情况之一作为我的输出:"P","Q","..","PQ","RS",.."PQR", "PQS"..."PQRS"。我计划做一个开关盒,因为所有这些组合都会调用不同的代码。

使用以

布尔元组为键的查找映射:

std::map<std::tuple<bool,bool,bool,bool>,value> map;

查找值就是这样:

map.find({T==P,T==Q,T==R,T==S});

(当然,将其包装在查找函数中以使其更容易(。

地图的值将确定您实际需要的值。 它可以是一个字符串、一个数值,甚至是在找到键时要执行的 std::function (lambda(。

或者,您也可以使用 unordered_map,但您需要自己提供哈希函数,因为 STL 没有元组的默认哈希函数。

可以使用按位运算将四个测试的结果合并为单个0..15整数值。请注意,每个比较仅执行一次。

获得结果值后,可以将其用作数组或std::vector的索引,也可以用作关联容器的键查找。在这个简单的例子中,我用了一个switch的结果。

int mask = (P == T) << 3 | (Q == T) << 2 | (R == T) << 1 | (S == T);
switch (mask) // 0..15
{
    case 15: // PQRS
        break;
    case 14: // PQR
        break;
    case 13: // PQS
        break;
    case 12: // PQ
        break;
    case 11: // PRS
        break;
    case 10: // PR
        break;
    case 9: // PS
        break;
    case 8: // P
        break;
    case 7: // QRS
        break;
    case 6: // QR
        break;
    case 5: // QS
        break;
    case 4: // Q
        break;
    case 3: // RS
        break;
    case 2: // R
        break;
    case 1: // S
        break;
    case 0: // none
        break;
}       

尝试匹配位字段。

如果我们考虑一个 4 位字段 0000,我们可以设置第一个位,如果T==P第二个位,如果T==Q,依此类推:

unsigned index{(P==T?1U:0U)|(Q==T?2U:0U)|(R==T?4U:0U)|(S==T?8U:0U)};

然后只需索引到一个数组中。

注意1:我注意到另一个答案使用相同的技巧和switch,这也将起作用。

注意 2:您可以将此实现视为使用"完美哈希"的哈希表。

#include <iostream>
#include <string>
//Actual Solution Starts Here.
const std::string match_data[] {
 "",//0000
 "P",//0001
 "Q",//0010
 "PQ",//0011
 "R",//0100
 "PR",//0101
 "PQ",//0101
 "PQR",//0111
 "S",//1000
 "PS",//1001
 "QS",//1010
 "PQS",//1011
 "RS",//1100
 "PRS",//1101
 "PQS",//1101
 "PQRS"//1111
};

std::string match(int T, int P, int Q, int R, int S){
    unsigned index{(P==T?1U:0U)|(Q==T?2U:0U)|(R==T?4U:0U)|(S==T?8U:0U)};
    return match_data[index];
}
//Actual Solution Ends Here.
//The rest is a trivial test harness...
bool error{false};
int check(int T, int P, int Q, int R, int S, const std::string& expect){
    const auto result{match(T,P,Q,R,S)};
    if(result!=expect){
        std::cout<<"Error ("<<T<<','<<P<<','<<Q<<','<<R<<','<<S<<")=="<<result<<"!="<<expect<<std::endl;
        error=true;
        return 1;
    }
    return 0;
}

int main() {
    int errors{0};
    errors+=check(7,1,2,3,4,"");
    errors+=check(7,7,2,3,4,"P");
    errors+=check(9,1,9,3,4,"Q");
    errors+=check(117,1,6,117,4,"R");
    errors+=check(13,1,7,3,13,"S");
    errors+=check(132,132,132,132,132,"PQRS");
    errors+=check(98,98,98,3,4,"PQ");
    errors+=check(9876,56,87,9876,4,"R");
    errors+=check(1,1,0,1,0,"PR");
    errors+=check(78,78,78,78,0,"PQR");
    if(errors==0&&!error){
        std::cout<<"Success"<<std::endl;
    }else{
        std::cout<<"ERRORS: "<<errors<<std::endl;
    }
    return 0;
}