开发者

Truth table as the keys for a dictionary

I have six boolean flags that are independent of each other so there are 64 possible combinations. These flags should determine the value of some string. This string can have seven different values. I think implementing this as a large if-statement is a bad idea so I thought of creating a truth table where each combination determines a specific outcome:

Key            Value
0,0,0,0,0,0 -> "A"
0,0,0,0,0,1 -> "A"
0,0,0,0,1,0 -> "B"
0,0,0,0,1,1 -> "C"
0,0,0,1,0,0 -> "A"
...

This looks remarkably like a dictionary but what would be the best key implementation (in C#)? The smallest poss开发者_如何学Pythonible key would be a byte that I mask the options into. However, this wouldn't improve the readability of my code.

Are there other solutions for this?


You could represent the 6 bool options as an enum with the FlagsAttribute, and rely on the readability of your enum names.

Edit, for example:

[Flags]
enum MyFlagSet : byte
{
    NoFlags = 0,
    Flag1 = 1 << 0,
    Flag2 = 1 << 1,
    Flag3 = 1 << 2,
    Flag4 = 1 << 3,
    Flag5 = 1 << 4,
    Flag6 = 1 << 5
};

Dictionary MyDictionary = new Dictionary<MyFlagSet, string>()
                          {
                              {MyFlagSet.NoFlags, "Q"},
                              {MyFlagSet.Flag1 | MyFlagSet.Flag2, "A"},
                              {MyFlagSet.Flag3 | MyFlagSet.Flag5 | MyFlagSet.Flag6, "B"}
                          };


This is an old question - and answered, but since ran across this while looking for a solution myself, here's my take on it.

public interface ITruthTable<in T1, in T2, in T3, in T4>
{
    bool GetValue(T1 obj1, T2 obj2, T3 obj3, T4 obj4);
}
public static class TruthTable
{
    private interface IMutableTable
    {
        void AddRow(bool v1, bool v2, bool v3, bool v4, bool result = false);
    }

    private sealed class Table<T1, T2, T3, T4>: ITruthTable<T1, T2, T3, T4>, IMutableTable
    {
        private readonly Func<T1, bool> _column1;
        private readonly Func<T2, bool> _column2;
        private readonly Func<T3, bool> _column3;
        private readonly Func<T4, bool> _column4;

        private readonly List<bool[]> _rows = new List<bool[]>();
        private readonly List<bool> _results = new List<bool>();

        private readonly bool _default;

        public Table(Func<T1, bool> column1, Func<T2, bool> column2, Func<T3, bool> column3, Func<T4, bool> column4, bool defaultValue)
        {
            _column1 = column1;
            _column2 = column2;
            _column3 = column3;
            _column4 = column4;

            _default = defaultValue;
        }

        #region IMutableTable<T1,T2,T3,T4> Members

        void IMutableTable.AddRow(bool v1, bool v2, bool v3, bool v4, bool result)
        {
            _rows.Add(new bool[4]);
            var row = _rows[_rows.Count - 1];
            row[0] = v1;
            row[1] = v2;
            row[2] = v3;
            row[3] = v4;

            _results.Add(result);
        }

        #endregion

        #region ITruthTable<T1,T2,T3,T4> Members

        public bool GetValue(T1 obj1, T2 obj2, T3 obj3, T4 obj4)
        {
            var v1 = _column1(obj1);
            var v2 = _column2(obj2);
            var v3 = _column3(obj3);
            var v4 = _column4(obj4);

            for (int i = 0; i < _rows.Count; i++)
            {
                var row = _rows[i];
                if ((row[0] == v1) && (row[1] == v2) && (row[2] == v3) && (row[3] == v4))
                    return _results[i];
            }

            return _default;
        }

        #endregion
    }

    public static ITruthTable<T1, T2, T3, T4> Create<T1, T2, T3, T4>(Func<T1, bool> column1, Func<T2, bool> column2, Func<T3, bool> column3, Func<T4, bool> column4, bool defaultValue = false)
    {
        return new Table<T1, T2, T3, T4>(column1, column2, column3, column4, defaultValue);
    }

    public static ITruthTable<T1, T2, T3, T4> Row<T1, T2, T3, T4>(this ITruthTable<T1, T2, T3, T4> table, bool v1, bool v2, bool v3, bool v4, bool result)
    {
        (table as IMutableTable).AddRow(v1, v2, v3, v4, result);
        return table;
    }
}

class Program
{
    static void Main(string[] args)
    {
        var testTable = TruthTable.Create<bool, bool, bool, bool>
            (b => b /*Column description*/ , b => b /* Column 2 */ , b => b, b => b, defaultValue: false)
        .Row(false,                          false,                  false,  false, false)
        .Row(false,                          true,                   false,  true,  true)
        .Row(true,                           true,                   true,   false, false)
        .Row(true,                           false,                  true,   true,  true);

        var result = testTable.GetValue(false, true, false, true);
    }

Simple explanation: The funcs provided accept values for each column and convert them to bools. A simple loop then finds the first correct match and returns it's result value or returns the default value specified. the last value in each .Row call is the result if the inputs match that row.

Of course, this solution is for 4 generic parameters but it is simple to write tables for more or less parameters than this. Also, the simple case above uses a bool to bool mapping for the value extractors but in real world apps it might need to accept some other type of object and convert it to a bool input value for that column.

It was type-safe enough and good enough my needs, hope it helps someone else, too.


The simplest way:

struct KeyThing
{
  public int a,b,c,d,e,f;
}

The preferred way would be using bitmasks.


You could create an enum with the FlagsAttribute, which may make your code easier to read, but you will have to make up 64 names!


Use a bitmask to create a int and store your values in a regular hash?

ie:
0,0,0,0,0,0 = 0
0,0,0,0,0,1 = 1
0,0,0,0,1,0 = 2

and then hash[0] = "a" and so on


If you encapuslate the six-booleans-to-string function into a separate class, then the readability of the code becomes trivially improved regardless of the implementation details. And the implementation can change based on performance needs that arise.

(I am going to make up a name to illustrate.)

public static class RobotEmotionDescriptions
{
    public static string GetDescription(bool isHurting, bool isAwake, 
           bool isBrightlyLit, bool isInQuitePlace, bool isPlayingChess, 
           bool isTumpedOver)
    {
        ... // Details don’t matter.
    }
}

So I think the bitmapped byte would be an excellent first-pass to an implementation.


You could represent your bool options as strings, e.g.
“011011”
then just use a Dictionary

(this may be a good option if you wish to let the user change the mappings, as reading strings from a file is easy)

However if you will be using them much, use a flags enum as per Luke’s answer.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜