加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c# – 是否有一种“聪明”的方式来打破嵌套循环?

发布时间:2020-12-15 23:24:58 所属栏目:百科 来源:网络整理
导读:(现在我主要使用C#.欢迎其他语言的想法,但如果可以,请将它们翻译成C#,并且要明确.) 我一次又一次遇到的是嵌套循环,搜索一些2D数组以找到一个元素(通常是一些对象),然后必须对其进行操作.所以当然,一旦你找到那个对象,就应该打破这两个循环,这样你就不必不必
(现在我主要使用C#.欢迎其他语言的想法,但如果可以,请将它们翻译成C#,并且要明确.)

我一次又一次遇到的是嵌套循环,搜索一些2D数组以找到一个元素(通常是一些对象),然后必须对其进行操作.所以当然,一旦你找到那个对象,就应该打破这两个循环,这样你就不必不必要地继续搜索你已经找到的东西(特别是在可以遍历指数巨大数组的嵌套循环中).

以下代码是我目前的首选方式:

Obj O = null;
bool KeepLooping = true;

for (int j = 0; j < height && KeepLooping; j++)
{
    for (int i = 0; i < width; i++)
    {
        if (ObjArray[i,j] != null && ObjArray[i,j].property == search_value)
        {
            O = ObjArray[i,j]; // you found it,now remember it
            KeepLooping = false; // clear the flag so the outer loop will break too
            break;
        }
    }
}

感谢Erik Funkenbusch,如果我们这样做,它会变得更加优雅:

Obj O = null;
for (int j = 0; j < height && O == null; j++) // much,much better idea to check O for null in the outer loop
{
    for (int i = 0; i < width; i++)
    {
        if (ObjArray[i,now remember it
            break;
        }
    }
}

不再需要那个讨厌的额外布尔值!

然而,寻求替代或更好的解决方案仍在继续.这些年来,我尝试了很多其他的方法,但发现它们并不是因为某种原因而变得那么好:

>将j(外循环迭代器)设置为高于高度的值,这将触发它自动中断.不理想,因为有时你想记住你发现它的i和j值.
>在2D阵列上使用foreach.不太理想,因为foreach不会让你操纵集合(删除或添加它,这通常是我搜索对象的原因).
>只需将2个循环放在一个除了查找并返回O之外什么都不做的函数中.返回有效地打破了两个循环.很多时候这没关系,但并非总是如此.我这样做是为了非常通用的搜索,但也有很多“群组搜索”,我想集体化遍历.在这些情况下,我找到2个或更多的对象(有时在同一个2D数组中),记住它们,然后才会中断两个循环.
>使用转到? (哇,这可能是goto的唯一合法使用吗?它比KeepLo??oping标志更具可读性,特别是如果我们有3个或更多循环.)不理想,因为同事会尖叫血腥谋杀.在C#中,goto之后会有正确的垃圾清理吗?
>抛出自定义异常? idk,我从未尝试过,但它看起来不像我目前喜欢的方式.
>一旦找到了正确的对象,在内部循环中进行所有对象操作,然后返回;这可能会很快变得凌乱.有时,对象操作涉及自己的循环.

由于User_PWY,还有一个非常聪明的第7种方式:

int size = width*height; // save this so you dont have to keep remultiplying it every iteration
for (int i = 0; i < size; i++)
{
   int x = i % width; // ingenious method here
   int y = i / width; // ingenious method here

   O = ObjArray[x,y];

   if (O != null)
       break; // woohoo!
}

这有效地将2D阵列压缩成一个用于迭代的循环.然而,一些批评指出,与i或j相比,mod和除法运算符相当缓慢,因此它可能会更慢(请记住我们正在处理谁知道什么大小的2D数组).就像我评论的那样,应该有一种方法可以在一次操作中得到除法和余数,因为我非常确定x86汇编代码具有DIV操作码,它将商和余数存储在单独的寄存器中,所有这些都在一个DIV指令中.但是如何在C#中使用它,idk.

如果C#允许你命名循环(如L1和L2)然后执行类似L1.break()的操作,那将是很好的.无论你在哪个循环中.唉……用这种语言做不到. (有没有一些秘密的方法可以使用宏来做到这一点?)是否有一个C#6.0实现了这个功能?

编辑:在我看来,我判断他们的优雅和速度的解决方案.请记住,我们正在处理嵌套循环,这可能会成倍增长.额外的操作或比较可能会有所不同.

好吧,好吧,告诉我你喜欢的方式,特别是如果这里没有列出的话.

解决方法

for (int i = 0; i < width*height; i++)
{
   int x=i%width,y=i/width;
   //dostuff
}

我喜欢这种访问2d数组的方式.

评论1)
有许多评论担心mod(%)运算符可能代价高昂,但这是我们正在讨论的整数运算,我认为它应该与其他解决方案没有区别.

评论2)
关于宏.我找不到代码但设法简单地生成了一个代码.

#define FOR2DARRAY(WIDTH,HEIGHT) 
    for (int i = 0,x = 0,y = 0; i < (WIDTH)*(HEIGHT); i++,x=i%(WIDTH),y=i/(HEIGHT))

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读