我有三个需要以某种方式设置的变量。例如,
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或switch,或者switch / if combo:
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
和set_difference
的项目中我有另一种类似的情况,但我不能在这里使用它,并且必须使用更少的STL和更老的学校C ++解决方案。
有什么想法吗?
答案 0 :(得分:1)
您可以将此视为第二种解决方案的改进(优雅):
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;
}
您可以通过映射两个值来进一步改进它,对于(1<<a)|(1<<b)
的每个值:
static int first[] = {2,1,3,1,2,1};
static int second[] = {3,3,3,2,2,1};
int index = ((1<<a)|(1<<b))/2-1; // reduce from [2,4,6,8,10,12] to [0,1,2,3,4,5]
c = choose(first[index],second[index]);
你有一个没有switch
,while
或任何其他条件陈述的优雅解决方案......
答案 1 :(得分:1)
第二眼看,首先选择唯一元素更有意义,其次是其他两个元素。这种方式更干净,但可能仍然不优雅。
如果你坚持choose
的离散变量实现,它可能看起来像这样:
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);
}
对于只有三个变量,我会采用最简单的方法并使用您发布的while
循环:
do
{
c = choose(1, 2, 3);
}
while(c == a || c == b);
如果您确实需要确定性运行时的保证,可以尝试以下方法。但是,我不确定每个人都会发现它更“优雅”,我不认为可维护性是值得的。
if(a != b)
{
c = 6 - (a + b);
}
else
{
c = choose(0, 1);
c = 1 + (a + c) % 3;
}
考虑到问题是如何设置的,所有这些都不是可扩展的,但是在需要使其更加通用之前,我会假设YAGNI。
答案 2 :(得分:1)
你真的只有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,您可以使用与c++
类似的while循环替换它:
c = 1;
while(a == c || b == c)
c++;
如果c
需要chosen
你提交的while循环对我来说似乎很好。
答案 3 :(得分:0)
一个简单的解决方案是将链表(通过引用)传递到choose
函数中。选择的元素将从列表中删除并返回。对函数的后续调用将有越来越少的元素可供选择。
您必须注意列表为空时并相应地处理它。
如果允许a
和b
相同,则choose
将不是您用于确定c
的功能。在这种情况下,有一个单独的函数chooseC
,它接受一个选定值列表(通过常量引用)和一个可用值列表(按值)。从可用值中删除所选值,然后从剩下的内容中选择。
答案 4 :(得分:0)
也许是这样的:
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
此解决方案可确保
a != b && a != c