真相表作为字典的键

时间:2010-09-09 12:58:24

标签: c# algorithm dictionary

我有六个相互独立的布尔标志,因此有64种可能的组合。这些标志应该确定某些字符串的值。该字符串可以有七个不同的值。我认为将它作为一个大的if语句实现是一个坏主意所以我想创建一个真值表,其中每个组合确定一个特定的结果:

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"
...

这看起来非常像字典,但最好的关键实现是什么(在C#中)?最小的可能键是byte,我将选项掩盖到其中。但是,这不会提高我的代码的可读性。

还有其他解决方案吗?

7 个答案:

答案 0 :(得分:7)

您可以使用FlagsAttribute将6个bool选项表示为枚举,并依赖于枚举名称的可读性。

编辑,例如:

[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"}
                          };

答案 1 :(得分:3)

这是一个老问题 - 并且已经回答了,但是在我自己寻找解决方案的过程中遇到了这个问题,这就是我的看法。

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);
    }

简单说明:funcs为每列提供了接受值并将它们转换为bools。然后,一个简单的循环找到第一个正确的匹配并返回它的结果值或返回指定的默认值。每个.Row调用的最后一个值是输入与该行匹配的结果。

当然,这个解决方案适用于4个通用参数,但编写表格的参数比这个更多或更少。此外,上面的简单案例使用bool来为值提取器进行bool映射,但在实际应用中,它可能需要接受其他类型的对象并将其转换为该列的bool输入值。

这种类型足够安全且我的需求足够好,希望它也可以帮助其他人。

答案 2 :(得分:1)

最简单的方法:

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

首选方法是使用位掩码。

答案 3 :(得分:0)

您可以使用FlagsAttribute创建枚举,这可能会让您的代码更容易阅读,但您必须补充64个名字!

答案 4 :(得分:0)

使用位掩码创建一个int并将值存储在常规哈希中吗?

即:
0,0,0,0,0,0 = 0
0,0,0,0,0,1 = 1
0,0,0,0,1,0 = 2

然后hash [0] =“a”依此类推

答案 5 :(得分:0)

如果将6-booleans-to-string函数封装到一个单独的类中,那么无论实现细节如何,代码的可读性都会得到很大的改进。并且实施可以根据出现的性能需求而改变。

(我打算用一个名字来说明。)

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

所以我认为位图字节对于实现来说是一个很好的第一遍。

答案 6 :(得分:0)

您可以将bool选项表示为字符串,例如
“011011”
然后只使用字典

(如果您希望让用户更改映射,这可能是一个不错的选择,因为从文件中读取字符串很容易)

但是,如果您将使用它们,请根据Luke的回答使用标记枚举。