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

Eri*_*ikE 5 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
Run Code Online (Sandbox Code Playgroud)

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

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

例:

if (oldvalue == 0 && newvalue == 0) return;
if (oldvalue != 0) X();
if (newvalue != 0) Y();
Z(oldvalue != 0 ? -1 : 0 + newvalue != 0 ? 1 : 0);
Run Code Online (Sandbox Code Playgroud)

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

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;
}
Run Code Online (Sandbox Code Playgroud)

这实际上比我正在处理的情况稍微简单一些.如果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
Run Code Online (Sandbox Code Playgroud)

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

LBu*_*kin 10

让我们从另一个角度来看你的问题.在设计代码体时,我尝试应用以下原则:

  1. 说得对.
  2. 讲清楚.
  3. 简明扼要.
  4. 快一点.... 以该顺序.

所有这些在某种程度上都是主观的.然而,合理的人倾向于找到共同点 - 而且他们的对立面往往更加一致.但除此之外......

这里的首要任务是确保您的代码正常运行.显然,有多个实现可以实现这一点 - 但我还要补充一点,很容易证明实现是正确的.实现此目的的一种方法是使代码读取更像规范(稍后将详细介绍).

第二个优先事项是确保将来,当开发人员(包括原始作者!)查看此代码时,他们将能够立即了解它正在做什么.实现越复杂(读取:花哨),开发人员就越难以立即理解代码正在做什么.

第三个优先事项 - 简短,简洁的代码,与前两个部分相反.希望使代码更简洁,可能会导致您使用比实际解决问题所需的更复杂的构造.虽然保持代码简短很重要,但我们不应该通过使其难以理解密集来实现这一点.

最后一个优先事项 - 表现 - 只有在重要时才重要.这意味着,除非您已经执行了分析并将其识别为系统中的瓶颈,否则我不应该从性能的角度对实现进行复杂化.

现在我们已经看过应该推动我们决策的原则,让我们将它们应用到手头的问题中.您已经提供了关于代码应该如何表现的非常清晰的规范.让我们试着坚持下去:

void YourMethod( int oldValue, int newValue )
{
    bool oldValueNonZero = oldValue != 0;
    bool newValueNonZero = newValue != 0;

    if( oldValueNonZero ) { X(); }
    if( newValueNonZero ) { Y(); }
    if( oldValueNonZero && newValueNonZero ) { Z(); }
}
Run Code Online (Sandbox Code Playgroud)

那么为什么我喜欢这个特定的实现呢.让我们分解吧.

首先,请注意我已选择创建临时布尔值来捕获测试旧/新值的结果,以确定它们是否为非零值.通过捕获这些值,我避免多次执行计算,并且我还使代码更具可读性(见下文).

其次,通过选择描述性名称oldValueNonZero,newValueNonZero我正在使实施清楚地表明我的期望.这既提高了代码的可读性,又清楚地向未来必须阅读它的开发人员传达了我的意图.

,注意身体if()测试被包裹在{}括号-这有助于减少这样的机会,未来的实施变化将打破行为-由于意外,包括一个新的情况下,例如.使用单行ifs是未来问题的一个方法.

最后,我不会尝试将比较短路并尽早退出功能.如果性能非常重要,提前退出可能会有用.但是,如果只有一个出口点(1),它会更容易理解方法的行为.

这段代码是否符合规范的要求?我相信是这样.

是否易于阅读和理解.至少对我而言,我会说是的.

这段代码是最紧凑或最复杂的逻辑短路方式吗?几乎肯定不是......但在我看来,除了弥补这一点之外,还有其他特质.

无论您是否喜欢这种特殊的代码结构,在某种程度上都是品味和风格的问题.但我希望我所阐述的关于如何组织它的原则可能有助于你在未来做出这样的决定.

你已经表明你有时遇到类似的"逻辑网格"问题,但是案例数量更多的问题.由于两个不同的原因,这些问题可能会变得复杂:

  1. 参数可以增加的值的数量 - 它们可以采用一般形式MxN.
  2. 维度数量增加 - 换句话说,规则中包含更多变量:MxNxOxP...xZ.

该问题的一个通用解决方案(如另一个响应所示)是将解决方案编码为多维矩阵 - 并为每个案例定义一组操作.但是,规则完全可能重叠 - 为简单起见,可能需要将等效案例合并在一起.

我对处理一般案件的回应是......这取决于它.如果条件可以减少到极少数情况,那么命令式if/else逻辑可能仍然是解决问题的最佳方法.如果条件的数量非常大,那么使用声明性方法可能是有意义的,其中使用某种查找表或矩阵来编码案例.

1> - 只有一个方法的单个出口点的原则的一个常见例外是前提条件.通过首先检查所有/任何前提条件来避免嵌套和反转逻辑是更清洁的,并且如果它们被违反则失败(退出)该方法.