[英]Simple selection from finite list
I have three variables that need to be set in a certain way. 我有三个需要以某种方式设置的变量。 For example,
例如,
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.
The easiest way I can think of for setting c is to use a loop: 我想到的设置c的最简单方法是使用循环:
do
{
c = choose(1, 2, 3);
}
while(c == a || c == b);
Alternatively I could use ifs or a switch, or a switch/if combo: 另外,我可以使用ifs或switch或switch / 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:
…
Neither of these seems elegant, and the latter is just bloody ugly. 这些看上去都不优雅,而后者只是血腥的丑陋。
I had another similar situation in a project where I've used std::set
and set_difference
, but I can't use that here, and have to use a rather less STL like and more old school C++ solution. 我在一个使用
std::set
和set_difference
的项目中遇到了另一set_difference
,但是我不能在这里使用它,而必须使用一个set_difference
STL的和更老的C ++解决方案。
Any ideas please? 有什么想法吗?
You may consider this, as an improvement (elegance-wise) of your second solution: 您可能会认为这是对第二种解决方案的改进(在优雅方面):
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;
}
You can further improve it by mapping two values to choose from, for each value of (1<<a)|(1<<b)
: 对于每个
(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]);
And there you have an elegant solution without switch
, while
or any other conditional statement... 在那里,您可以找到一个优雅的解决方案,
while
无需switch
, while
或任何其他条件语句...
On second look, it makes more sense to pick the unique element first , followed by the other two. 从第二个角度看,首先选择唯一元素 ,然后再选择其他两个元素更有意义。 It's cleaner this way, though maybe still not elegant.
这样比较干净,尽管可能仍然不够优雅。
If you stick with the discrete variable implementation of choose
, it might look something like this: 如果你坚持使用离散变量执行的
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);
}
Using an array is even cleaner and can be made a little more general with little effort: 使用数组甚至更干净,可以毫不费力地使数组变得更通用:
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);
}
For only three variables, I would take the simplest approach and use the while
loop you posted: 对于仅三个变量,我将采用最简单的方法并使用您发布的
while
循环:
do
{
c = choose(1, 2, 3);
}
while(c == a || c == b);
If you really need that guarantee of deterministic run-time, you could try something like the following. 如果您确实需要确定性运行时的保证,则可以尝试以下操作。 However, I'm not sure everyone would find it more "elegant" and I don't think the maintainability hit is worth it.
但是,我不确定每个人都会觉得它“更优雅”,并且我认为不影响可维护性是否值得。
if(a != b)
{
c = 6 - (a + b);
}
else
{
c = choose(0, 1);
c = 1 + (a + c) % 3;
}
Neither is all that scalable given how the question is set up, but until a need to make it more general arises, I'd assume YAGNI . 鉴于问题的设置方式,所有这些都没有那么可扩展,但是在需要使其变得更笼统之前,我假设使用YAGNI 。
Do you really just have 3 values like this or is this a minimized example? 您是否真的只有3个这样的值,或者这是一个最小化的示例? For this case I'd straight-forward exclude taken values
对于这种情况,我会直接排除采用的值
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;
If the values are 1,2,3 you could replace that with a while loop that does c++
similar to yours: 如果值为1,2,3,则可以使用while循环替换该循环,该循环执行与您的
c++
类似的c++
:
c = 1;
while(a == c || b == c)
c++;
If c
needs to be chosen
the while loop you presented seems fine to me. 如果需要
chosen
c
,那么您呈现的while循环对我来说似乎很好。
An easy solution would be to pass a linked list (by reference) into the choose
function. 一个简单的解决方案是将链接列表(通过引用)传递到
choose
函数中。 An element that is chosen would be removed from the list and returned. 所选元素将从列表中删除并返回。 Subsequent calls to the function would have fewer and fewer elements to choose from.
随后调用该函数将有越来越少的元素可供选择。
You would have to take note of when the list is empty and handle it accordingly. 您将必须注意列表何时为空并进行相应处理。
If a
and b
are allowed to be the same, then choose
would not be the function you are using for determining c
. 如果允许
a
和b
相同,那么choose
将不是您用来确定c
的函数。 In that case, have a separate function chooseC
that takes a list of chosen values (by constant reference) and a list of available values (by value). 在那种情况下,有一个单独的函数
chooseC
,它接受一个选定值的列表(按常量引用)和一个可用值的列表(按值)。 Remove the chosen values from the available values, and pick from what is left. 从可用值中删除选择的值,然后从剩余的值中进行选择。
Maybe something like this: 也许是这样的:
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
This solution ensures that 该解决方案可确保
a != b && a != c
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.