题
当我确信标记的中断/继续完全是“不”之后 这里, ,我需要帮助从我的代码中删除标签。
我有一个方阵和一个长度相同的向量。该向量中已经有一些值,并且根据矩阵中的值,向量在循环中发生变化。
我希望,代码片段基本上是可以理解的......
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 );
}
请说服我,有一个更易读/更好的没有标签的版本。
解决方案
看看目前提出的解决方案:
它们看起来都比原来的可读性差,因为它们涉及在代码机制而不是算法本身上花费更多的代码
其中一些已损坏,或者在编辑之前已损坏。最可恶的是,人们必须认真思考如何在没有标签的情况下编写代码而不破坏任何东西。
有些会因为运行相同的测试两次而导致性能损失,这可能并不总是微不足道的。另一种方法是存储和传递布尔值,这会变得很难看。
将代码的相关部分重构为方法实际上是无操作的:它重新排列代码在文件中的布局方式,但对其执行方式没有影响。
所有这些让我相信,至少在这个问题的情况下,标签是正确的解决方案,不需要被重构。当然,在某些情况下标签使用不正确,应该被重构。我只是认为不应该将其视为牢不可破的规则。
其他提示
@Patrick你假设调用 setValueInVector( v, idx );在第二个循环结束时就可以了。如果代码要在逻辑上相同,则必须重写为如下所示:
for( int idx = 0; 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 );
}
编辑:完全正确,你是安德斯。我已经编辑了我的解决方案以考虑到这一点。
通过阅读你的代码。
- 我注意到您消除了 conditionAtVectorPosition 处的无效向量位置,然后删除 anotherConditionAtVector 处的无效行。
- 似乎检查 anotherConditionAtVector 处的行是多余的,因为无论 idx 的值是什么,anotherConditionAtVector 仅取决于行索引(假设 anotherConditionAtVector 没有副作用)。
所以你可以这样做:
- 首先使用conditionAtVectorPosition 获取有效位置(这些是有效列)。
- 然后使用 anotherConditionAtVector 获取有效行。
- 最后,使用条件AtMatrixRowCol 使用有效的列和行。
我希望这有帮助。
@尼古拉斯
其中一些已损坏,或者在编辑之前已损坏。最令人讨厌的是,人们必须在不用标签而不打破任何内容的情况下对如何编写代码进行认真思考。
我有不同的观点:其中一些被打破了,因为很难找出原始算法的行为。
我意识到这是主观的,但我在阅读原始算法时没有任何问题。它比提议的替代方案更短、更清晰。
该线程中的所有重构所做的都是使用其他语言功能来模拟标签的行为 - 就好像您将代码移植到没有标签的语言一样。
有些会因为运行相同的测试两次而导致性能损失,这可能并不总是微不足道的。另一种方法是存储和传递布尔值,这会变得很难看。性能损失很小。不过我同意运行两次测试并不是一个好的解决方案。
我认为问题是如何删除标签,而不是如何优化算法。在我看来,原始发帖者不知道如何在没有标签的情况下使用“继续”和“中断”关键字,但当然,我的假设可能是错误的。
当谈到性能时,这篇文章没有提供有关其他函数实现的任何信息,因此据我所知,他们可能还通过 FTP 下载结果,因为结果由编译器内联的简单计算组成。
话虽如此,从理论上讲,两次进行相同的测试并不是最佳选择。
编辑:再想一想,这个例子实际上并不是标签的可怕使用。我同意 “转到是禁忌”, ,但不是因为这样的代码。这里标签的使用实际上并不会显着影响代码的可读性。当然,它们不是必需的,并且很容易被省略,但不要仅仅因为“使用标签不好”在这种情况下不是一个好的论据而使用它们。毕竟,正如其他人已经评论的那样,删除标签并不会使代码更易于阅读。
这个问题不是关于优化算法 - 但无论如何谢谢;-)
在我编写它时,我认为带标签的 continue 是一个可读的解决方案。
我问了这么一个 问题 关于 Java 中标签的约定(标签是否全部大写)。
基本上每个答案都告诉我“不要使用它们 - 总是有更好的方法!重构!”。所以我发布这个问题是为了寻求一个更具可读性(因此更好?)的解决方案。
到目前为止,我还没有完全相信迄今为止提出的替代方案。
请不要误会我的意思。大多数时候,标签都是邪恶的。
但就我而言,条件测试非常简单,算法取自数学论文,因此很可能在不久的将来不会改变。因此,我更喜欢立即显示所有相关部分,而不必滚动到另一个名为 checkMatrixAtRow(x) 之类的方法。
特别是在更复杂的数学算法中,我发现很难找到“好的”函数名称 - 但我想这是另一个问题
我认为标记循环非常罕见,您可以选择任何适合您的标记方法 - 您所拥有的使您的继续意图非常清晰。
在带头建议重构原始问题中的循环并现在看到有问题的代码之后,我认为您在那里有一个非常可读的循环。
我想象的是一段非常不同的代码——把实际的例子放在上面,我可以看到它比我想象的要干净得多。
对于造成的误解,我深表歉意。
这对你有用吗?我将内部循环提取到一个方法 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;
}
我不太确定理解第一个继续。我会复制 Gishu 并写一些类似的内容(如果有一些错误,抱歉):
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;
}
@萨迪:
它们看起来都比原来的可读性差,因为它们涉及在代码机制而不是算法本身上花费更多的代码
将第二个循环外部化到算法之外并不一定可读性较差。如果方法名称选择得当,可以提高可读性。
其中一些已损坏,或者在编辑之前已损坏。最可恶的是,人们必须认真思考如何在没有标签的情况下编写代码而不破坏任何东西。
我有不同的观点:其中一些已被破坏,因为很难弄清楚原始算法的行为。
有些会因为运行相同的测试两次而导致性能损失,这可能并不总是微不足道的。另一种方法是存储和传递布尔值,这会变得很难看。
性能损失很小。不过我同意运行两次测试并不是一个好的解决方案。
将代码的相关部分重构为方法实际上是无操作的:它重新排列代码在文件中的布局方式,但对其执行方式没有影响。
我不明白有什么意义。是的,它不会改变行为,就像......重构?
当然,在某些情况下标签使用不正确,应该被重构。我只是认为不应该将其视为牢不可破的规则。
我完全同意。但正如您所指出的,我们中的一些人在重构这个示例时遇到了困难。即使最初的示例是可读的,但也很难维护。