代码之家  ›  专栏  ›  技术社区  ›  Ronald Wildenberg

作为字典键的真值表

  •  3
  • Ronald Wildenberg  · 技术社区  · 14 年前

    我有六个彼此独立的布尔标记,所以有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 回复  |  直到 12 年前
        1
  •  7
  •   luke    14 年前

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

    编辑,例如:

    [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"}
                              };
    
        2
  •  3
  •   Ani    12 年前

    这是一个古老的问题,我回答了这个问题,但由于我自己在寻找解决方案时遇到了这个问题,所以我现在就来回答这个问题。

    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-to-bool映射,但在现实世界中,它可能需要接受其他类型的对象,并将其转换为该列的bool输入值。

    这是类型足够安全和良好的我的需要,希望它也帮助别人。

        3
  •  1
  •   leppie    14 年前

    最简单的方法:

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

    首选的方法是使用位掩码。

        4
  •  0
  •   Polyfun MicBehrens    14 年前

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

        5
  •  0
  •   Fredrik Leijon    14 年前

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

    IE:
    0、0、0、0、0、0=0
    0、0、0、0、0、1=1
    0,0,0,01,1,0=2

    然后hash[0]=“a”等等

        6
  •  0
  •   Jeffrey L Whitledge    14 年前

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

    所以我认为位图字节是实现的一个很好的第一步。

        7
  •  0
  •   Ian Ringrose    14 年前

    您可以将bool选项表示为字符串,例如
    __011100__
    那就用字典吧

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

    但是,如果您要经常使用它们,请根据Luke_窆的答案使用Flags枚举。