简体   繁体   English

从有限列表中轻松选择

[英]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::setset_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无需switchwhile或任何其他条件语句...

Edit 编辑

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 . 如果允许ab相同,那么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.

相关问题 没有显示列表中的选定选择? - Not displaying a chosen selection from a list? QT从文件和文件夹列表中选择多个项目 - QT Multiple item selection from a list of files and folders 防止在修改项目列表时更改可编辑的QComboBox选择 - Prevent editable QComboBox selection from changing when item list modified 从数字列表中随机选择一个偏向最低数字的数字 - Random selection of a number from a list of numbers that is biased toward the lowest number 将元素从一个列表添加到另一个列表的简单方法 - Simple way to add elements from one list to another list 当使用优化标志计算简单的有限差分时,clang ++ v6,7&8 bug /错误结果 - clang++ v6, 7 & 8 bug/wrong result when computing a simple finite difference with optimization flag 通过while循环从用户读取有限输入到整数变量中 - Reading a finite input from user through while loop into an integer variable 来自有限基类集的排列的大量 C++ 对象 - Multitude of C++ objects from permutations on finite set of base classes C ++:从带孔的多边形中获取简单多边形的列表 - C++: Get list of simple polygons from polygon with holes 从给定位置开始的简单链接列表中删除元素 - Delete elements from a simple linked list starting at given position
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM