for(int x = 0; x < max_x_index; x++){
for(int y = 0; y < max_y_index; y++, count++){
some2DarrayRepresentedBy1D[count] = ...;
}
}
这是否会被视为不良做法?以下是实现相同结果的更好方法:
for(int x = 0; x < max_x_index; x++){
for(int y = 0; y < max_y_index; y++){
some2DarrayRepresentedBy1D[count] = ...;
count++;
}
}
例如,允许您同时进行代码审查还是为第一个示例标记?晦涩吗?
#1 楼
我同意OP的观点,因为第二个代码块将是最好的方法。原因-可读性。在我看来,在for循环语句中递增的变量仅应用于计数我们循环的次数。
count
可以在循环之前设置,也可以在几个不同的循环中递增/递减。但是无论哪种情况,count
都不用于跟踪当前循环的进度-在这种情况下,y
就是这样。因此,出于可读性考虑,我认为这是最佳做法仅在for循环行本身中增加用于循环通过for循环的变量。
#2 楼
在到目前为止的所有答案中,我认为Charlie74与我所做的推理最接近。for循环包括三个部分:
for (initialization; termination; increment) {
statement(s)
}
我认为只有附加终止的东西才应该是增量的一部分。换句话说,如果该值不属于终止条件,那么它就不应该是增量的一部分。 br />
在这种情况下,计数不影响终止条件,因此它不属于增量部分。.
对于它的价值,有一个我仍然会做一些不同的事情:
第二个示例中您有错别字....(在
x
中缺少x <
,而缺少y <
)[此问题已解决现在。] 我将把count ++作为数组分配的一部分(我认为它属于该数组):
for(int x = 0; x < max_x_index; x++){
for(int y = 0; y < max_y_index; y++){
some2Darray[count++] = ...;
}
}
在这种情况下讨论
++count
与count++
是否是其中一种情况,如果将
i++
更改为++i
,它将更改数组中分配的内容?您能解释一下...吗?这里....是的,这是前增量或后增量差异显着的情况之一。 Wikipedia对此进行了介绍。
预递增运算符
++count
递增count变量。后递增运算符count++
也会递增计数变量。区别在于,尽管++count
和count++
都是表达式,但表达式的结果值却不同。重要的是要了解
count++
是一个表达式的含义。表达式是产生值的东西。在上下文array[count] = 1
中,count
是一个表达式,它是带有值的东西。相反,该表达式可以是常量(array[0]
),函数(array[getNextIndex()]
),甚至可以是由子表达式和运算符组成的更复杂的表达式(array[5 - 3]
)。因此,count++
是一个表达式。同样,它修改了count
变量中的值。类似地,++count
是一个表达式,它也修改了count
的值。它们之间的区别不是它们对count
的作用,而是表达式的值。 /> 使用
count++
时,表达式的值就是count
递增之前的值。使用
++count
时,表达式的值就是count
递增之后的值。因此,在上面的示例中,比较了两种不同的情况:
int count = 0;
array[count++] = 1;
vs.
int count = 0;
array[++count] = 1;
在第一个示例中,表达式
count++
的值为0(增量之前的值),因此,索引0
o处的值如果将array
设置为1
。即它等效于:int count = 0;
array[count] = 1;
count = count +1;
在第二个示例中,表达式
++count
的值为1(递增后的值),结果,值为将1
的索引array
设置为1
。即它等效于:int count = 0;
count = count + 1;
array[count] = 1;
很明显,通过使用
++count
,我们将开始在索引1而不是0处添加数据,并且存在出局的风险。到达数据末尾时的边界操作。在将数据添加到数组的情况下(例如此问题的处理方式),将计数器设置为要使用的“下一个”插槽是有意义的,然后进行后递增操作,以便“使用”下一个插槽,然后增加它,使其再次指向下一个插槽。
这样做的好处是,最后,
count
也是您在阵列中插槽的数量烦躁不安的是,出现了另一个问题(在数组中找到所有具有最大值的索引),其中一个潜在的答案很好地说明了这一点。
评论
\ $ \ begingroup \ $
因此,如果循环条件包含例如&& count
–没人远离SE
2013年12月8日在16:19
\ $ \ begingroup \ $
当然可以。
\ $ \ endgroup \ $
–rolfl
13年12月8日在16:27
\ $ \ begingroup \ $
@rolfl,这是在其中将i ++更改为++ i时会更改数组中分配的内容的实例之一吗?您能再解释一下吗,所以当有人输入[++ count]时不会感到困惑
\ $ \ endgroup \ $
–马拉奇♦
2013年12月10日19:02
\ $ \ begingroup \ $
@Malachi它将更改其在数组中的分配位置。对于x = 0; y = 0,您将通过count ++分配给位置0,并通过++ count分配给位置1。 (假设循环之前count =0。)
\ $ \ endgroup \ $
– ANeves认为SE是邪恶的
2013年12月10日19:42
#3 楼
我认为@rolfl在正确的轨道上for (int x = 0; x < max_x_index; x++) {
for (int y = 0; y < max_y_index; y++) {
some2Darray[count++] = ...;
}
}
使用for循环而不是
/* initialization */;
while (/* condition */) {
/* body */;
/* increment */;
}
/>
是为了使您的代码具有与目的相符的立即可识别的外观。因此,初始化,条件和增量部分都应达到相同的目的。您应该避免在for循环标头中引入“脱离主题”的代码。此外,
some2Darray[count++] = ...
仅在一行中有效地传达了您要填充的数组-编写一个元素,然后移动此处的其他用户表示反对,因为循环体中存在某些意外的流量控制,可能会绕过
count++
。该代码的目标似乎是生成一个平面2D数组,因此我怀疑是否涉及到break
或continue
。但是,如果仍然担心一致性,则可以使用断言。int count = 0;
for (int x = 0; x < max_x_index; x++) {
for (int y = 0; y < max_y_index; y++) {
some2Darray[count++] = ...;
}
}
Debug.Assert(count == max_x_index * max_y_index);
或者,完全消除
count
,而仅使用x * max_y_index + y
。评论
\ $ \ begingroup \ $
正如那些指出流量控制可能错过尾随增量的人之一,我同意在给定的用法中这不会发生。但是,在对代码评审中接受的内容提供一般指导时,必须考虑这一点。
\ $ \ endgroup \ $
– Michael Urman
2013年12月8日22:24
\ $ \ begingroup \ $
“ Count”比“ x * max_x_index + y”更清晰,并且如果数组变得更加复杂(例如,如果某些迭代将零个元素或多个元素推入多个元素),则它可以继续工作
\ $ \ endgroup \ $
–马特
2013年12月9日,下午1:54
#4 楼
这种更改存在正确性问题。在给定的示例中,变换后的循环是等效的(除了增量发生的顺序;我假设它们都是int
变量,因此不太可能发生问题。)循环中可以包含
continue
语句,这两者之间突然之间有很大的不同:int count = 0;
for (int x = 0; x < MAX; ++x, ++count)
{
: : :
if (sometest())
continue;
: : :
}
int count = 0;
for (int x = 0; x < MAX; ++x)
{
: : :
if (sometest())
continue;
: : :
++count;
}
在后面的代码块中,仅当循环主体完成时,
count
才增加。在前一个代码块中,每当开始下一个循环迭代时,count
就会递增。用例可以确定其中哪个是正确的,并且在这些情况之间的决定可能值得评论,以免稍后再破坏它。请注意,将
++count
移至第二个示例的开头将使其有所不同。与第一个示例更相似,但在您的示例中将需要使用count - 1
索引数组。作为类似的选择,如果只使用一次索引,则可以使用诸如some2Darray[count++]
之类的结构,而不要使用其中的任何一种,尽管像原始的第二个代码块一样,这也可能会因早期continue
的行为而产生错误,并且有些人会认为它的可读性较低。 br />#5 楼
此线程上的几个人都在讨论for循环的工作原理,但很少有人提到for循环和while循环之间的语义差异。当程序员在阅读代码时遇到for循环时,语义是循环肯定会终止并在一定范围的数字或元素列表上进行迭代。这就是为什么所有程序员都立即知道以下循环的原因,并且在脑海中很容易理解和解析它们。
// iterate over the integer range N...M
for(int i = N; i < M; i++)
func(N)
// iterate over every element in array
for(int i = 0; i < array.length; i++)
func(array[i]);
// iterate over some singly linked list
for(item = list; item != NULL item=item->Next)
func(item);
// iterate over some doubly linked list:
for(item = listHead->Next; item != listHead; item = item->Next)
func(item);
因此,您的前两个数组精心设计,并且在代码审查期间快速且易于理解。这两个列表在[0,0]到[max_x_index,max_y_index]的所有项上迭代x和y。但是如果您毒害了两个for循环之一,则它们看起来不再正常通过将一些与语义无关的变量(计数)添加到其中一个循环中,突然整个循环变得难以理解。计数与循环中的[x,y]迭代无关。它在语义上与some2DArray中有多少个元素相关,并且将它们彼此移开会使整个代码更难阅读,不可避免地也难以维护和调试。
实践是修改变量以使其含义更接近语义,这有助于理解代码。为此,您应该在应更改计数的位置修改count-不是在循环迭代时,而是在通过内联增量修改some2DArray时:
some2DArray[count++] = ...
或紧随其后:
some2DArray[count] = ...
count++
因此,回答您的问题,在for循环中增加多个变量几乎从来不是一个好主意。 for循环应专门处理要迭代的修改元素,而不要理会其他变量。违反此规则会混淆程序的语义,并使其难以阅读。
#6 楼
您在评论中提到,最终结果最终将是将数组的每个成员设置为x * y
x
的每个迭代。 count
将以值x * y
结尾。 – afuzzyllama 1小时前所以这是我的想法,而不是这样做:
for(int x = 0; x < max_x_index; x++){
for(int y = 0; y < max_y_index; y++, count++){
{
some2DarrayRepresentedBy1D[count] = ...;
}
}
执行此操作
for (int i = 0; i < max_x_index * max_y_index; i++)
{
some2DarrayRepresentedBy1D[i] = ...;
}
很明显,我不知道您在
...
中做什么,但是如果您嵌套在两个For
循环中,并且这里没有太多其他事情,那么我认为您是每次都在做同样的事情。这看起来像您可能正在寻找的答案,否则,您需要显示更多代码。评论
\ $ \ begingroup \ $
大概原始代码中的省略号是someProcess(someMatrix [x] [y])。有了这个建议,它必须是someProcess(someMatrix [i / max_y_index] [i%max_y_index])。我不会在清晰度或性能上有所改善。
\ $ \ endgroup \ $
– 200_success
2013年12月12日23:16
\ $ \ begingroup \ $
@ 200_success,这个公式对我来说似乎不合适,但是如果是这种情况,那么像我的其他答案一样执行它就很有意义。但即使OP完全在问其他问题,该信息也应该是问题
\ $ \ endgroup \ $
–马拉奇♦
2013年12月12日23:21
\ $ \ begingroup \ $
@Malachi-问题的关键是要询问count在for声明中的位置以及它是否常见。
\ $ \ endgroup \ $
–afuzzyllama
2013年12月13日,0:56
\ $ \ begingroup \ $
@afuzzyllama我知道,我一句话一句话地读了这个问题,意识到我离你的要求很远。但我希望它也为您提供了另一种查看代码的方式。从200_success的评论来看,尽管我认为这个特定的答案不起作用。我的其他答案应该对您来说很好,并且似乎没有违反任何规则
\ $ \ endgroup \ $
–马拉奇♦
2013年12月13日在3:27
#7 楼
UPDATEMatt提出了非常好的要点,但我仍然相信下面的两个代码块将与Matt在其回答中所说的一样。
count
每次迭代都会增加for循环的内部,因此它正在两个代码块中更改应更改的位置。不应递增未在For循环的声明中声明的变量。
那样说,您可以这样操作
for(int x = 0, int count = 0; x < max_x_index; x++){
for(int y = 0; y < max_y_index; y++, count++){
{
some2DarrayRepresentedBy1D[count] = ...;
}
}
如果您不编写代码,这将非常令人困惑,从而违反了KISS原则和/或POLS / POLA原则(最不惊奇/惊讶的原则)
离开Rolfl给出的答案,这将减少编写代码的时间,并且可能会更简洁一些,请再次评论此代码包含您的工作方式以及执行此操作的原因。
for(int x = 0, int count = 0; x < max_x_index; x++){
for(int y = 0; y < max_y_index; y++){
{
some2DarrayRepresentedBy1D[count++] = ...;
}
}
一点点的知识
>您可以做什么
for(int x = 0; x < max_x_index; x++){
for(int y = 0; y < max_y_index; y++){
{
some2DarrayRepresentedBy1D[count] = ...;
count++;
}
}
因为增量器仅用于进行循环(取决于您的计数,[此示例将为您提供完全不同的结果])
for (int x = 0, int y = 100;x < max_x_index, y > max_y_index; x++, y--){
some2DarrayRepresentedBy1D[count] = ... ;
count++;
}
我只举一个例子,您可以在一个for循环中使用两个增量器,但是OP发布的不是这些实例之一。
评论
\ $ \ begingroup \ $
我认为不是KISS,而是最不惊奇的原则?
\ $ \ endgroup \ $
–没人远离SE
2013年12月10日18:57
\ $ \ begingroup \ $
@没人就是我要评论的人:“你是说POLS” :)
\ $ \ endgroup \ $
– Mathieu Guindon♦
2013年12月10日19:06
\ $ \ begingroup \ $
如果要将变量放入for循环中并消除多余的行,也许不是多余的注释或字符,这是增加该变量的最佳方法。我很乐意看到性能统计数据将两种方式相互对照
\ $ \ endgroup \ $
–马拉奇♦
2013年12月10日19:26
评论
我看到这个问题同时被标记为“ C”和“ Java”。两种语言中的惯用语代码是不同的,因此最佳答案可能在不同的语言中也有所不同-例如,rolfl的some2Darray [count ++]在C语言中很常见,但我在Java中却很少见。啊,我知道不是你,但是@ 200_success添加了标签...
@Izkata some2Darray [count ++]在Java中与在C中一样有效。没有理由或证据表明它在Java中不那么流行。
@ 200_success我从没说过有效性,我知道这对两种语言都是有效的。但是习惯用法并不总是跨语言的。
嗯,当然可以。谢谢@afuzzyllama。