2010-09-09 88 views
3

我有六个彼此独立的布尔标志,所以有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

您可以将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"} 
          }; 
+0

Pfew,64个有意义的名字。我已经觉得很难拿出一个。如果我选择这个选项,我仍然会遇到问题,根据六个标志中的每一个的值确定正确的键。除非我从'1,2,4,8,16,32'中为每个标志分配一个int并将它们放在一起。这使我非常接近使用'byte'或'int'作为关键字。 – 2010-09-09 13:10:21

+0

@Ronald Wildenberg - 双OR-在一起的权力选项正是FlagsAttribute的意图。所以你只需要六个命名值而不是64. – 2010-09-09 13:13:07

+0

@Jeffrey - 你说得对,我的错。你不需要考虑64个名字。谢谢。 – 2010-09-09 13:15:42

1

最简单的方法:

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

的优选方式将被使用位掩码。

+0

你的意思是'公共bool a,b,c,d,e,f'? – 2010-09-09 13:03:46

+0

@Ronald Wildenberg:'bool'也可以工作。 – leppie 2010-09-09 15:03:41

0

您可以创建与FlagsAttribute枚举,这可能使你的代码更容易阅读,但你将不得不作出了64名!

+0

FlagsAttribute方法只需要6个名称(或7个,如果你想包含没有标志集,0)。 – luke 2010-09-09 13:26:48

0

使用位掩码创建一个int并将您的值存储在常规散列中?

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

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

0

如果时封装六布尔值到字符串的功能到一个单独的类,则该代码的可读性变得平凡不管改善实施细节。实施可以根据出现的性能需求进行更改。

(我准备做一个名字来说明。)

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

所以我认为,位图字节将是一个很好的第一传球的实现。

0

您可以将您的bool选项表示为字符串,例如,
“011011”
就用字典

(这可能是一个很好的选择,如果你希望让用户改变的映射,如阅读字符串从一个文件很容易)

不过,如果你将会使用它们,按照Luke的回答使用标志枚举。

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

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

这是类型安全的,足够好我的需求,希望它可以帮助别人。

+0

时间是完美的。我试图弄清楚我将如何提出一个干净的方法来测试每个4个布尔选项的16个用例。 +1 – 2012-03-30 17:06:22