繁体   English   中英

真相表作为字典的键

[英]Truth table as the keys for a 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 ,我将选项掩盖到。 但是,这不会提高我的代码的可读性。

还有其他解决方案吗?

您可以使用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"}
                          };

这是一个老问题 - 并且回答了,但是自从我自己寻找解决方案时遇到了这个问题,这是我的看法。

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为每列提供了接受值并将它们转换为bool。 然后,一个简单的循环找到第一个正确的匹配并返回它的结果值或返回指定的默认值。 每个.Row调用中的最后一个值是输入与该行匹配的结果。

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

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

最简单的方法:

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

首选方法是使用位掩码。

您可以使用FlagsAttribute创建一个枚举,这可能使您的代码更容易阅读,但您必须组成64个名称!

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

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

然后散列[0] =“a”等等

如果将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.
    }
}

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

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

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

但是,如果您将使用它们,请按照Luke的答案使用标记枚举。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM