在代码中有效地表达2x2逻辑网格

时间:2010-08-27 18:38:02

标签: c# language-agnostic grid logic

在事件处理程序中,我正在响应值的更改。我可以访问旧值和新值,并希望根据更改的内容执行某些操作。

每个不同的结果将执行动作/函数X,Y或Z的某种组合.Z接受介于-1和1之间的参数。执行这些操作的顺序并不重要。

查看以下逻辑网格。旧值是最左边的标签列,新值是标签的第一行:

          New:
          0          !=0
          --------   -------
Old:  0 | nothing    Y, Z(1)
    !=0 | X, Z(-1)   X, Y    -- Z(0) is okay but not required for this quadrant

表示这个的好方法是什么?

我在C#工作,但会接受任何语言的答案,因为它不是真正的语言问题 - 我可以翻译任何内容。

示例:

if (oldvalue == 0 && newvalue == 0) return;
if (oldvalue != 0) X();
if (newvalue != 0) Y();
Z(oldvalue != 0 ? -1 : 0 + newvalue != 0 ? 1 : 0);

我认为看起来很不错,但还有其他方法可以做到。

int which = (oldvalue == 0 ? 0 : 1) + (newvalue == 0 ? 0 : 2)

switch (which) {
   case 1:
      X(); Z(-1);
      break;
   case 2:
      Y(); Z(1);
      break;
   case 3:
      X(); Y();
      break;
}

这实际上比我正在处理的情况稍微简单一些。如果oldvalue和newvalue非零并且彼此相等,则将newvalue视为0。

随意回答给定或附加约束。还有一点点,但我认为开始时太多了。如果事情看起来很有意思,我会在这里或在一个新问题中介绍其余部分。

我想我是在问这个问题,因为我最终会经常使用这些逻辑网格,而且它们并不总是2x2,有时它们会更大。很高兴地注意到我可以处理一些带有整个“条纹”的响应,就像注意到每次oldvalue!= 0时都会完成X,但似乎我开始遇到一个需要处理一些表达逻辑的模式它更普遍而不是费力地将其转换为if then else语句。我的意思是,如果我能提供一种逻辑网格并让编译器找出处理它的最佳方法,那真的很酷。

做一些疯狂的头脑风暴:

Conditions:
oldvalue == 0 ? 0 : 1
newvalue == 0 ? 0 : 2

Actions:
X = {false, true, false, true}
Y = {false, false, true, true}
Z(-1) = true where condition = 1
Z(1) = true where condition = 2

你有什么想法?我会奖励任何物质上的参与。

3 个答案:

答案 0 :(得分:10)

答案 1 :(得分:2)

您实际上可以使用多维数组来快捷测试和分支进程。如果查找的结果不是固定值,而是某种需要完成的工作,则可以使该数组成为委托数组,并使用方法或可执行代码(lambdas)填充它。

像这样:

private void Y() { }
private void X() {}
private void Z(int n) {}

private void example(int oldvalue, int newvalue)
{
    var array = new Action[2, 2];
    array[0, 0] = () => { };
    array[0, 1] = () => { Y(); Z(1); };
    array[1, 0] = () => { X(); Z(-1); };
    array[1, 1] = () => { X(); Y(); };

    // invoke
    array[oldvalue == 0 ? 0 : 1, newvalue == 0 ? 0 : 1]();
}

您还可以使用内联初始化程序初始化状态数组,但我发现在显式语句中突破单元格分配更容易阅读并跟踪其中的内容。

可以在包含此示例函数的类的构造函数中提前完成数组的初始化。然后,示例函数中的执行将减少为

  1. 评估oldvalue == 0
  2. 评估newvalue == 0
  3. 索引到数组中以检索委托
  4. 执行委托以执行操作
  5. 这种技术导致非常非常少的执行开销(快速),可以很好地扩展到任意数量的维度,并保留代码和逻辑表之间的相关性,这使得以后与混乱相比更容易理解和修改各地的if语句。

答案 2 :(得分:1)

额外信用解决方案

这是一个非常有趣的主题,有一些来自贡献者的深刻见解。我认为你的问题得到了回答,所以我会专注于额外的功劳。最简单的方法是更新您的表格并将其应用于您最喜欢的解决方案。

让我们以完全描述每列条件的方式来表达问题。如果新值等于零​​或旧值,我们将从第一列执行操作。如果新值非零并且不等于旧值,我们将从第二列执行操作。

          New == 0 || New == Old    New != 0 && New != Old
          ----------------------   ------------------------
Old == 0 | nothing                  Y, Z(1)
Old != 0 | X, Z(-1)                 X, Y    -- Z(0) is okay but not required for this quadrant

因此,在dthorpe的解决方案中,我们会将newValue == 0替换为newValue == 0 || newValue == oldValue

private void example(int oldvalue, int newvalue)
{
    var array = new Action[2, 2];
    array[0, 0] = () => { };
    array[0, 1] = () => { Y(); Z(1); };
    array[1, 0] = () => { X(); Z(-1); };
    array[1, 1] = () => { X(); Y(); };

    array[oldvalue == 0 ? 0 : 1, newValue == 0 || newValue == oldValue ? 0 : 1]();
}

在LBushkin的解决方案中,我们将newValue != 0替换为newValue != 0 && newValue != oldValue并更新相应的变量名以保持可读性。我也要把代码位混淆:

void YourMethod( int oldValue, int newValue )
{
    bool oldValueNonZero = oldValue != 0;
    bool newValueDifferentAndNonZero = newValue != 0 && newValue != oldValue;
    int zCondition = 0;

    if( oldValueNonZero ) { X(); zCondition--;}
    if( newValueDifferentAndNonZero ) { Y(); zCondition++;}
    if( zCondition != 0 ) { Z(zCondition); }
}

多田!