重构标记循环

时间:2020-03-05 18:40:40  来源:igfitidea点击:

当我确信标记的中断/继续完全是"麻烦"之后,我需要帮助将标记从代码中删除。

我有一个正方形矩阵和一个具有相同长度的向量。向量中已经有一些值,取决于矩阵在循环中更改的值。

我希望代码片段基本上是可以理解的

vectorLoop:
for( int idx = 0; idx < vectorLength; idx++) {
    if( conditionAtVectorPosition( v, idx ) ) continue vectorLoop;

    matrixLoop:
    for( rowIdx = 0; rowIdx < n; rowIdx++ ) {
        if( anotherConditionAtVector( v, rowIdx ) ) continue matrixLoop;
        if( conditionAtMatrixRowCol( m, rowIdx, idx ) ) continue vectorLoop;
    }
    setValueInVector( v, idx );
}

请说服我,这是一个更具可读性/更好的版本,没有标签。

解决方案

回答

轻轻松松,我的好人。

for( int idx = 0; idx < vectorLength; idx++) {
  if( conditionAtVectorPosition( v, idx ) ) continue;

  for( rowIdx = 0; rowIdx < n; rowIdx++ ) {
    if( anotherConditionAtVector( v, rowIdx ) ) continue;
    if( conditionAtMatrixRowCol( m, rowIdx, idx ) ) break;
  }
  if( !conditionAtMatrixRowCol( m, rowIdx, idx ) )
    setValueInVector( v, idx );
}

编辑:完全正确,你是安德斯。我还对解决方案进行了编辑,以考虑到这一点。

回答

@Patrick我们假设调用setValueInVector(v,idx);在第二个循环的末尾就可以了。如果代码在逻辑上是相同的,则必须将其重写为如下形式:

for( int idx = 0; idx

回答

这对我们有用吗?我将内部循环提取到CheckedEntireMatrix方法中(我们可以比我更好地命名它)而且我的Java有点生锈。

for( int idx = 0; idx < vectorLength; idx++) {
    if( conditionAtVectorPosition( v, idx ) 
    || !CheckedEntireMatrix(v)) continue;

    setValueInVector( v, idx );
}

private bool CheckedEntireMatrix(Vector v)
{
    for( rowIdx = 0; rowIdx < n; rowIdx++ ) {
        if( anotherConditionAtVector( v, rowIdx ) ) continue;
        if( conditionAtMatrixRowCol( m, rowIdx, idx ) ) return false;
    }   
    return true;
}

回答

Gishu有一个正确的主意:

for( int idx = 0; idx < vectorLength; idx++) {
    if (!conditionAtVectorPosition( v, idx ) 
        && checkedRow(v, idx))
         setValueInVector( v, idx );
}

private boolean checkedRow(Vector v, int idx) {
    for( rowIdx = 0; rowIdx < n; rowIdx++ ) {
        if( anotherConditionAtVector( v, rowIdx ) ) continue;
        if( conditionAtMatrixRowCol( m, rowIdx, idx ) ) return false;
    }  
    return true;
}

回答

我不太确定首先要了解什么。

for( int idx = 0; idx < vectorLength; idx++) {
    if( !conditionAtVectorPosition( v, idx ) && CheckedEntireMatrix(v))
        setValueInVector( v, idx );
}

inline bool CheckedEntireMatrix(Vector v) {
    for(rowIdx = 0; rowIdx < n; rowIdx++)
        if ( !anotherConditionAtVector(v,rowIdx) && conditionAtMatrixRowCol(m,rowIdx,idx) ) 
            return false;
    return true;
}

回答

我会复制Gishu并写一些类似的东西(如果有一些错误,抱歉):

  • 我注意到我们消除了conditionAtVectorPosition处的无效矢量位置,然后删除了anotherConditionAtVector处的无效行。
  • 似乎检查anotherConditionAtVector上的行是多余的,因为无论idx的值是什么,anotherConditionAtVector仅取决于行索引(假定anotherConditionAtVector没有副作用)。

通过阅读代码。

  • 首先使用conditionAtVectorPosition(这些是有效列)获取有效位置。
  • 然后使用anotherConditionAtVector获取有效行。
  • 最后,使用有效列和行使用conditionAtMatrixRowCol。

因此,我们可以执行以下操作:

回答

我希望这有帮助。

  • 它们看起来都比原始的可读性差,因为它们涉及在代码的机制上而不是算法本身上花费更多的代码。
  • 其中一些已损坏,或者已被编辑。最可恶的事实是,人们不得不认真思考如何在不使用标签的情况下编写代码,而不破坏任何内容。
  • 有些测试会导致两次运行相同的测试而导致性能下降,但这并不总是微不足道的。替代方法是存储和传递布尔值,这变得很丑陋。
  • 将代码的相关部分重构为一种方法实际上是一项禁忌措施:它重新排列了代码在文件中的布局方式,但对代码的执行方式没有影响。

看到目前为止提出的解决方案:

回答

所有这些都使我相信,至少在所说的问题中,标签是正确的解决方案,不需要重构。当然,在某些情况下标签使用不正确,应将其重构。我只是认为不应该将其视为牢不可破的规则。

They all look less readable than the original, in that they involve spending more code on the mechanism of the code rather than on the algorithm itself

@Sadie:

Some of them are broken, or were before they were edited. Most damning is the fact that people are having to think quite hard about how to write the code without labels and not break anything.

将第二个循环外部化到算法外部不一定可读性较低。如果方法名称选择正确,则可以提高可读性。

Some come with a performance penalty of running the same test twice, which may not always be trivial. The alternative to that is storing and passing round booleans, which gets ugly.

我有不同的观点:它们中的一些被破坏了,因为很难弄清楚原始算法的行为。

Refactoring the relevant part of the code into a method is effectively a no-op: it rearranges how the code is laid out in the file, but has no effect on how it's executed.

性能损失很小。但是我同意两次运行测试不是一个好的解决方案。

Certainly there are cases where labels are used incorrectly and should be refactored away. I just don't think it should be treated as some unbreakable rule.

我不明白这一点。是的,它不会改变行为,例如...重构?

回答

我完全同意。但是正如我们所指出的那样,我们中有些人在重构此示例时遇到了困难。即使最初的示例可读,也很难维护。

Some of them are broken, or were before they were edited. Most damning is the fact that 
    people are having to think quite hard about how to write the code without labels and not 
    break anything.

@尼古拉斯

我有不同的观点:其中一些因为难以理解而被打破了
原始算法的行为。

我意识到这是主观的,但是阅读原始算法没有任何麻烦。它比拟议的替代产品更短,更清晰。

回答

Some come with a performance penalty of running the same test twice, which may not always be trivial. The alternative to that is storing and passing round booleans, which gets ugly.

对于造成误解,我深表歉意。

该线程中所有重构的作用是使用其他语言功能来模拟标签的行为,就像我们将代码移植到没有标签的语言一样。

我相信问题在于如何删除标签,而不是如何优化算法。在我看来,原始发布者没有意识到如何使用没有标签的'continue'和'break'关键字,但是,当然,我的假设可能是错误的。

在性能方面,该帖子未提供有关其他功能实现的任何信息,因此,据我所知,他们最好还是通过FTP下载结果,该结果由编译器内联的简单计算组成。

话虽如此,两次进行相同的测试在理论上并不是最佳的。

回答

编辑:再三考虑,该示例实际上并不是对标签的可怕使用。我同意" goto是no-no",但不是因为这样的代码。在这里使用标签实际上并不会以很大的方式影响代码的可读性。当然,它们不是必需的,可以轻易省略,但不能仅仅因为"使用标签是不好的"而不能使用它们,在这种情况下不是一个好参数。毕竟,删除标签并不能使代码更容易阅读,因为其他人已经对此进行了评论。

这个问题不是关于优化算法,而是无论如何都要感谢;-)

在我写这篇文章的时候,我认为标记为continu作为可读的解决方案。

我问了一个关于Java中标签约定的问题(是否带有大写字母)。

基本上,每个答案都告诉我"不要总有更好的方法!重构!"。因此,我发布了这个问题,以寻求一种更具可读性(因此更好的解决方案)。

到目前为止,到目前为止,我还不完全相信这些替代方案。

请不要误会我的意思。在大多数情况下,标签是邪恶的。

但就我而言,条件测试非常简单,该算法取自数学论文,因此很可能在不久的将来不会改变。因此,我宁愿一次看到所有相关部分,而不必滚动到另一个名为checkMatrixAtRow(x)的方法。

回答

尤其是在更复杂的数学算法中,我发现很难找到"好的"函数名,但是我想这是另一个问题

我认为带标签的循环非常少见,我们可以选择任何适合标签方法,使意图与继续完美地结合在一起。

在领导提出建议以重构原始问题中的循环并看到有问题的代码后,我认为我们那里的可读性非常好。

我想象的是截然不同的代码块来编写实际的示例,我发现它比我想象的要干净得多。

零散数量不匹配