C++ 有限列表中的简单选择

C++ 有限列表中的简单选择,c++,C++,我有三个变量需要以某种方式设置。比如说, int a, b, c; a = choose(1, 2, 3); // a can take the value 1 to 3 inclusive b = choose(1, 2, 3); // b can take the value 1 to 3 inclusive c = ?????? // c can't take either of the values in a or b. 设置c的最简单方法是使用循

我有三个变量需要以某种方式设置。比如说,

int a, b, c;
a = choose(1, 2,  3);   // a can take the value 1 to 3 inclusive
b = choose(1, 2,  3);   // b can take the value 1 to 3 inclusive
c = ??????              // c can't take either of the values in a or b.
设置c的最简单方法是使用循环:

do
{
    c = choose(1, 2,  3);
}
while(c == a || c == b);
或者,我可以使用ifs或开关,或开关/if组合:

a = choose(1, 2,  3);   
b = choose(1, 2,  3);   

switch(a){
    case 1:
        switch(b){
            case 1:
                c = choose(2, 3)
                break;
            case 2:
                c = 3;
                break;
            case 3:
                c = 2;
                break;
        }
        break;
    case 2:
        …
这两个看起来都不优雅,而后者则是非常丑陋的

我在一个项目中遇到了类似的情况,我使用了 STD::SET//COD>和 StIdSuff<<代码>,但是我不能在这里使用,并且必须使用一个相当少的STL类和更老的C++C++.E.P.解决方案。
有什么想法吗?

一个简单的解决方案是将链接列表(通过引用)传递到
choose
函数中。选择的元素将从列表中删除并返回。对函数的后续调用将有越来越少的元素可供选择

您必须注意列表何时为空,并相应地进行处理


如果允许
a
b
相同,则
choose
将不是用于确定
c
的函数。在这种情况下,可以使用一个单独的函数
chooseC
,该函数获取所选值的列表(通过常量引用)和可用值的列表(通过值)。从可用值中删除所选值,然后从剩下的值中选择。

可能是这样的:

int a, b, c;
int myList[]= {1, 2, 3};

a = choose(myList);   // if choose can take a list as input
b = choose(myList);

myList.remove(a);
myList.remove(b);

c = choose(myList);  // the selection from a and b are out of the list at this point
int choose(int, int); // two choice overload
int choose(int, int, int); // three choice overload

int main()
{
    int c = choose(1, 2, 3);

    int x = 1 + c % 3;
    int y = 1 + (c + 1) % 3;

    int a = choose(x, y);
    int b = choose(x, y);
}
此解决方案确保

a != b && a != c 

你可以认为这是你第二个解决方案的一个改进(优雅):

switch ((1<<a)|(1<<b))
{
    case  2: // a,b == 1,1
        c = choose(2,3);
        break;
    case  4: // a,b == 2,2
        c = choose(1,3);
        break;
    case  6: // a,b == 1,2 or 2,1
        c = 3;
        break;
    case  8: // a,b == 3,3
        c = choose(1,2);
        break;
    case 10: // a,b == 1,3 or 3,1
        c = 2;
        break;
    case 12: // a,b == 2,3 or 3,2
        c = 1;
        break;
}
开关((1Edit
第二种方法是,首先选择独特的元素,然后再选择其他两个元素,这样会更干净,尽管可能仍然不优雅

如果您坚持使用
choose
的离散变量实现,它可能会如下所示:

int a, b, c;
int myList[]= {1, 2, 3};

a = choose(myList);   // if choose can take a list as input
b = choose(myList);

myList.remove(a);
myList.remove(b);

c = choose(myList);  // the selection from a and b are out of the list at this point
int choose(int, int); // two choice overload
int choose(int, int, int); // three choice overload

int main()
{
    int c = choose(1, 2, 3);

    int x = 1 + c % 3;
    int y = 1 + (c + 1) % 3;

    int a = choose(x, y);
    int b = choose(x, y);
}
使用阵列更为简洁,只需稍加努力即可使其更加通用:

int choose(int[], int); // takes an array and its (effective) size

int main()
{
    constexpr int maxNum = 3;

    int choices[maxNum] = {1, 2, 3};

    //for larger values of maxNum, loop initialize:
    //for(int i = 0; i < maxNum; i++)
    //{
    //    choices[i] = i + 1;
    //}

    int c = choose(choices, maxNum);

    choices[c-1] = maxNum;

    int a = choose(choices, maxNum - 1);
    int b = choose(choices, maxNum - 1);
}
如果您真的需要确定性运行时的保证,您可以尝试下面的方法。但是,我不确定每个人都会觉得它更“优雅”,我认为维护性的损失是不值得的

if(a != b)
{
    c = 6 - (a + b);
}
else
{
    c = choose(0, 1);

    c = 1 + (a + c) % 3;
}

考虑到这个问题是如何设置的,也没有那么大的可伸缩性,但在需要将其变得更一般之前,我假设。

您真的只有3个这样的值,还是这是一个最小化的示例? 对于这种情况,我会直接排除所取的值

int a, b, c;
a = choose(1, 2,  3);   // a can take the value 1 to 3 inclusive
b = choose(1, 2,  3);   // b can take the value 1 to 3 inclusive
c = 1;
if(a == c || b == c)
  c = 2;
if(a == c || b == c)
  c = 3;
如果值为1,2,3,您可以用一个while循环来替换它,该循环与您的循环类似:

c = 1;
while(a == c || b == c)
    c++;

如果需要选择
c
while循环对我来说似乎很好。

我发现第一个循环很优雅。在
choose
中添加可选值,将其从使用中删除?
c=choose(1,2,3,a,b);
因此
choose
接受固定数量的元素?@jerry@crashmstr the choose()函数此时实际上并不存在,但如果存在,它可能只是:
returnrand()%3+1;
。我可以将choose作为变量编写,但由于它无法传递任何像
std::list
这样的智能数据,但只能在数组上运行,因此它似乎没有帮助?@peedurr我认为变量函数太过分了。请注意,大多数答案都假设存在
choose
,它可以提供不同数量的INPUT,虽然可能仍然是固定的。这可以通过重载或传入数组及其大小来实现,但考虑到您建议的实现的简单性质,您也可以轻松地直接调用
rand
。说到这一点,
rand()%3
,并不理想(尤其是因为听起来您是在受限环境中操作的),尽管它可能适合您的情况。即使假设
choose
可以这样修改,似乎这并不是OP想要的。根据这个问题,
a
b
可能都有相同的值,所以为
a
选择的任何内容都不应该从列表中删除。但是,我没有hink删除元素是正确的想法,特别是如果它要缩放的话。@jerry我刚刚在考虑这个问题。我假设
choose
会使它们都是唯一的,但这可能不是他所要求的。我的解释基于注释
//a可以取1到3的值,包括
//b可以接受包含1到3的值
,以及嵌套的
开关
语句有一种情况,即
a==1&&b==1
(因此
c=choose(2,3)
)。@jerry同意。我还添加了一节描述如何处理这种情况。
choose()
在这一点上是一个理论函数。我同意,如果可以传递一个
std::list
或类似的函数,那么删除项就好了。但是,它只能传递内部类型。这当然可能包括一个链接列表,但这似乎太复杂了。我越想它,越看这里的回复,我就越开始了ng认为
do
循环是最清晰、可读性最好的,如果不是此时的最佳解决方案的话。数组没有
remove
方法。另外,
choose
函数似乎没有在问题中使用数组。@jerry我不确定他有什么容器(1、2、3)除非选择只需要3个输入,否则可能需要一个数组而不是一个STD::在这种情况下,这个解决方案不会为我所用的“我不能在这里使用,而不得不使用一个更不太像STL和更老的学校C++解决方案”来表示“没有代码> STD< /COD>容器”。.
choose
接受问题中的单个
int
s,并且没有任何迹象表明OP的实际代码不同,所以这就是我的假设。虽然你可能是对的,但我理解这个问题意味着
c
仍然应该以相同的概率接受所有值。显然,这些解决方案是错误的