Pergunta

This is a small C++ application (and the table is not huge either) so if possible I would like to avoid include anything other than STL (and boost).

So to the problem:

I have a table of predefined matching of input and output conditions. This table contains 4 input variables (states), and their combination leads to 1 output variable. In essence:

output = f(a,b,c,d) 

i.e. "the output variable is a function of 4 input variables"

  • The output variable is an alarm and can take one of 3 states (ok,warning,fault).
  • "A" can take 1 of 3 states (say 0 or 1 or 2). Similarly
  • "B" can take 1 of 5 states
  • "C" can take 1 of 3 states
  • "D" can take 1 of 2 states

I want to provide the values to the input variables and get the output variable in return from this lookup table.

The table may look a bit like this:

A | B | C | D | output  
----------------------
1 | 3 | 0 | 1 | ok
0 | 2 | 1 | 2 | fault
0 | 0 | 0 | 0 | warning

... and so on. So the table will have no more than 150 entries (some optimisation has helped in this) which is not huge, but it is still too large if I try to create nested if-statments. What can I do to avoid huge if statements?

What I am looking for is a design pattern , or some good reference to read up on.

For example a sort of map which can hold 4 keys and 1 value would be ideal. Something like map would probably be ideal.

Foi útil?

Solução

Compile time solution 1 (clean)

You could "concatenate" your input values using tuples, and map these tuples to your output type. Here how to do it with a string as output:

string f (int a, int b, int c, int d) {
    using input =  tuple<int,int,int,int>;
    
    static map<input,string> mytable =  {
        { input{ 1, 3, 0, 1 }, "ok"}, 
        { input{ 0, 2, 1, 2 }, "fault"},
        { input{ 0, 0, 0, 0 }, "warning"}
    };
    return mytable[input{a,b,c,d}];
}

Here an online demo. Note that in the snippet above, if the combination doesn't exit a new combination is added to the map with an empty string. If you'd need to handle such errors, you could for example use mytable.at(...) instead of mytable[...] to throw an out of range exception

This approach is very powerful, because the tuples can aggregate the real types that your using for your input data. It's easy to maintain. And in addition the map search is very efficient: O(log n) compared to O(n) for an if-chain.

Compile time solution 2 (easy)

Another approach, could be to combine the states, if each has a numeric value. This is not so clean as the previous one ecause of the strong assumption on the input type, but it could do the trick:

string f (int a, int b, int c, int d) {
    // assumes that a,b,c and d are between 0 and 9 

    static map<int,string> mytable =  {
        { 1301, "ok"}, 
        { 0212, "fault"},
        { 0000, "warning"}
    };
    return mytable[a*1000+b*100+c*10+d];
}

Note that you could also use a switch statement in this case. Most of the modern compiler generate an optimiszed branch table, which will in any case be at least as performant than an if-chain if not more.

Run time approach (flexible)

A variant of the solution 1 could be to initialize the map at runtime. Instead of specifying an initializer list in the code, you'd just read once the input and output data from a file and build the map during your application startup.

May be it's not relevant for your problem. But I wanted to mention it here, because this may sometimes help to get a very flexible software that lets user choose the desired behavior at a minimal cost.

Outras dicas

This is a basic mathematical function that translates one domain into another. The suggestions given by previous members are excellent. I would keep the integer as a key, as it requires less space. The hexadecimal approach given by Cristophe might be the best solution here, as it provides you with an easy way of getting the individual inputs back if needed. Do not forget, in case you do not have outputs for all combinations of inputs, make sure you handle the default output properly.

Licenciado em: CC-BY-SA com atribuição
scroll top