避免在java中嵌套foreach循环

时间:2016-08-20 08:38:32

标签: java foreach nested processing-efficiency

自从我参加编码课以来已经有20年了。我不时地再次拿起它以获得乐趣,但我的代码很笨重而且低效的。

我有一个只有400多个元素的数组。我目前在该数组上运行了嵌套的foreach循环。

import acm.program.ConsoleProgram;
import java.awt.Color;
import acm.io.IODialog;
import java.text.*;
import static java.lang.Math.*;
import java.util.*;

/** Tests to see if user color matches sample colors */

public class test extends ConsoleProgram

{

   //defining sample colors

   Color[] dmc =
   {
      new Color(255,255,255),
      new Color(148,91,128),
      new Color(206,148,186),
      new Color(236,207,225),
      new Color(243,218,228),

   };

 public void run()
 {
    average();

 }

 //averages three colors, then tests for match to given color

 public void average()
 {

    //asks for user color
    IODialog dialog = new IODialog();
    int stitchRed= dialog.readInt("Enter red value: ");
    int stitchGreen= dialog.readInt("Enter green value: ");
    int stitchBlue= dialog.readInt("Enter blue value: ");
    Color stitchColor= new Color(stitchRed,stitchGreen,stitchBlue);

    //gets averages for dmc colors
    for (Color i:dmc)
    {
       for (Color j:dmc)
       {
          for (Color k:dmc)
          {
              int indexI = Arrays.asList(dmc).indexOf(i);
              int indexJ = Arrays.asList(dmc).indexOf(j);
              int indexK = Arrays.asList(dmc).indexOf(k);
              if(indexI <= indexJ && indexJ <= indexK)
              {
                 int iRed = i.getRed();
                 int jRed = j.getRed();
                 int kRed = k.getRed();
                 int iGreen = i.getGreen();
                 int jGreen = j.getGreen();
                 int kGreen = k.getGreen();
                 int iBlue = i.getBlue();
                 int jBlue = j.getBlue();
                 int kBlue = k.getBlue();
                 int redAverage = (iRed+jRed+kRed)/3;
                 int greenAverage = (iGreen+jGreen+kGreen)/3;
                 int blueAverage = (iBlue+jBlue+kBlue)/3;
                 Color colorAverage = new Color(redAverage,greenAverage,blueAverage);

                 //tests to see if any thread average equals user color
                 if (colorAverage.equals(stitchColor))
                 {
                    println("The color match is: " + i + ", " + j + ", " + k);
                 }
            }
         }
       }
     }

     println("no more matches");
   }
 }

这编译得很好,但运行速度很慢。

有没有更有效的方法呢? 可能是一种绕过筑巢的方法 - 具有以下效果:

for(Color i,j,k:dmc)

5 个答案:

答案 0 :(得分:1)

(我无法测试和调试代码,因为它不是SSCCE,因此我对任何错误都有所了解)
请考虑以下内容,详见评论:

Color[ ] dmc = {element1, element2, ...};

for( int i =0; i < dmc.length ; i++ )
 {

    //iterate only on values >= i 
   for( int j = i; j< dmc.length; j++ )
   {
       //loop only on values >= j
       for( int k = j; k < dmc.length ; k++ )
       {

           //not needed, you already have i, j, k 
           //int indexI = Arrays.asList(dmc).indexOf(i);
           //int indexJ = Arrays.asList(dmc).indexOf(j);
           //int indexK = Arrays.asList(dmc).indexOf(k);


           //condition is not needed. Allways true. 
           //if( indexI <= indexJ && indexJ <= indexK ) { }

           //bunch of code...

编辑:一个简短的演示,只打印出想要的事件:

        public static void main(String[] args) {

            Color[ ] dmc = {Color.AQUA, Color.AZURE, Color.BEIGE, Color.BLACK, Color.BLUE,
                    Color.BROWN, Color.CHOCOLATE, Color.CYAN,  Color.CRIMSON, Color.FUCHSIA};

            for( int i =0; i < dmc.length ; i++ )
             {

                System.out.printf("\n >>>>>> i= %s", i);
                //iterate only on values >= i
               for( int j = i; j< dmc.length; j++ )
               {
                   System.out.printf("\n         j= %s",j);

                   //loop only on values >= j
                   for( int k = j; k < dmc.length ; k++ )
                   {

                     System.out.printf("\n            k= %s",k);
                   }
               }
             }

        }

编辑II:在MCVE发布后,我通过添加fastEverage()方法对其进行了修改,该方法应与everage()进行相同的计算,迭代次数较少。
在我检查的单一颜色上,两种方法都有相同的输出:

import java.awt.Color;
import java.util.Arrays;

/** Tests to see if user color matches sample colors */
public class Test

{

    //defining sample colors

    Color[] dmc =
        {
                new Color(255,255,255),
                new Color(148,91,128),
                new Color(206,148,186),
                new Color(236,207,225),
                new Color(243,218,228),

        };

    //averages three colors, then tests for match to given color
    public void average()
    {

        //asks for user color
        int stitchRed =  203; 
        int stitchGreen= 164;
        int stitchBlue= 189;

        Color stitchColor= new Color(stitchRed,stitchGreen,stitchBlue);

        //gets averages for dmc colors
        for (Color i:dmc)
        {
            for (Color j:dmc)
            {
                for (Color k:dmc)
                {
                    int indexI = Arrays.asList(dmc).indexOf(i);
                    int indexJ = Arrays.asList(dmc).indexOf(j);
                    int indexK = Arrays.asList(dmc).indexOf(k);
                    if((indexI <= indexJ) && (indexJ <= indexK))
                    {
                        int iRed = i.getRed();
                        int jRed = j.getRed();
                        int kRed = k.getRed();
                        int iGreen = i.getGreen();
                        int kGreen = k.getGreen();
                        int jGreen = j.getGreen();
                        int iBlue = i.getBlue();
                        int jBlue = j.getBlue();
                        int kBlue = k.getBlue();
                        int redAverage = (iRed+jRed+kRed)/3;
                        int greenAverage = (iGreen+ jGreen + kGreen)/3;
                        int blueAverage = (iBlue+jBlue+kBlue)/3;

                        Color colorAverage = new Color(redAverage,greenAverage,blueAverage);

                        //tests to see if any thread average equals user color
                        if (colorAverage.equals(stitchColor))
                        {
                            System.out.println("The color match is: " + i + ", " + j + ", " + k);
                        }

                    }
                }
            }
        }

        System.out.println("no more matches");
    }

    //averages three colors, then tests for match to given color
    public void fastEverage()
    {

        //asks for user color
        int stitchRed =  203; 
        int stitchGreen= 164;
        int stitchBlue= 189;

        Color stitchColor= new Color(stitchRed,stitchGreen,stitchBlue);

        Color colorI, colorJ, colorK;

        for( int i =0; i < dmc.length ; i++ )
        {

            colorI = dmc[i];

            //iterate only on values >= i
            for( int j = i; j< dmc.length; j++ )
            {

                colorJ = dmc[j];

                //loop only on values >= j
                for( int k = j; k < dmc.length ; k++ )
                {

                    colorK = dmc[k];

                    int iRed = colorI.getRed();
                    int jRed = colorJ.getRed();
                    int kRed = colorK.getRed();
                    int iGreen = colorI.getGreen();
                    int kGreen = colorK.getGreen();
                    int jGreen = colorJ.getGreen();
                    int iBlue = colorI.getBlue();
                    int jBlue = colorJ.getBlue();
                    int kBlue = colorK.getBlue();
                    int redAverage = (iRed+jRed+kRed)/3;
                    int greenAverage = (iGreen+ jGreen + kGreen)/3;
                    int blueAverage = (iBlue+jBlue+kBlue)/3;

                    Color colorAverage = new Color(redAverage,greenAverage,blueAverage);

                    //tests to see if any thread average equals user color
                    if (colorAverage.equals(stitchColor))
                    {
                        System.out.println("The color match is: " + colorI + ", " + colorJ + ", " + colorK);
                    }

                }
            }
        }

        System.out.println("no more matches");
    }

    public static void main(String[] args)
    {
        new Test().average();
        new Test().fastEverage();

    }
} 

在这个测试用例中,两种方法之间的运行时差异很大:

  

以毫秒为单位运行everage()的时间84752814

     

以纳秒为单位运行fastEverage()的时间76497255

答案 1 :(得分:1)

它等于@C0der的答案,只是对问题的变量使用相同的名称。

    for (int indexI = 0; indexI < dmc.length; indexI++) {
        Color i = dmc[indexI];
        for (int indexJ = indexI; indexJ< dmc.length; indexJ++) {
            Color j = dmc[indexJ];
            for (int indexK = indexJ; indexK< dmc.length; indexK++) {
                Color k = dmc[indexK];
                //....
            }
        }
    }

编辑:

public void average() {
    //asks for user color
    IODialog dialog = new IODialog();
    int stitchRed = dialog.readInt("Enter red value: ");
    int stitchGreen = dialog.readInt("Enter green value: ");
    int stitchBlue = dialog.readInt("Enter blue value: ");
    Color stitchColor = new Color(stitchRed, stitchGreen, stitchBlue);
    for (int indexI = 0; indexI < dmc.length; indexI++) {
        Color i = dmc[indexI];
        for (int indexJ = indexI; indexJ < dmc.length; indexJ++) {
            Color j = dmc[indexJ];
            for (int indexK = indexJ; indexK < dmc.length; indexK++) {
                Color k = dmc[indexK];
                int iRed = i.getRed();
                int jRed = j.getRed();
                int kRed = k.getRed();
                int iGreen = i.getGreen();
                int jGreen = j.getGreen();
                int kGreen = k.getGreen();
                int iBlue = i.getBlue();
                int jBlue = j.getBlue();
                int kBlue = k.getBlue();
                int redAverage = (iRed + jRed + kRed) / 3;
                int greenAverage = (iGreen + jGreen + kGreen) / 3;
                int blueAverage = (iBlue + jBlue + kBlue) / 3;
                Color colorAverage = new Color(redAverage, greenAverage, blueAverage);
                //tests to see if any thread average equals user color
                if (colorAverage.equals(stitchColor)) {
                    System.out.println("The color match is: " + i + ", " + j + ", " + k);
                }
            }
        }
    }

    System.out.println("no more matches");
}

答案 2 :(得分:0)

考虑到你在if语句中过滤掉了许多组合,一个优化就是使用for循环,只迭代你实际想要处理的元素而不是for-each-loops。例如。 i&lt; = j表示你可以在i开始迭代。

根据评论中所述的意图,可能会有进一步的改进。

答案 3 :(得分:0)

您可以尝试类似

的内容
for( x=1;x<401;x++ )
{
    Color j= dmc[x];
    Color k= dmc[x+1];
    int indexI = Arrays.asList(dmc).indexOf(i);
    int indexJ = Arrays.asList(dmc).indexOf(j);
    int indexK = Arrays.asList(dmc).indexOf(k);
    if( indexI <= indexJ && indexJ <= indexK )
    {
        //bunch of code...

或者,您可以尝试在java.lang.Object中定义的equals方法。希望这会有所帮助。

答案 4 :(得分:0)

只是一个想法。您可以拆分搜索。有可能在第一次搜索中找到匹配项。如果是这样,那么你不需要搜索其余的匹配。如果没有,你可以继续搜索匹配。

int i,j,k;    
for(i=0;i<100;i++){
   for(j=i;j<100;j++){
      for(k=j;k<100;k++){
         //..do stuffs.....//
       } 
   }
}
if(matchnotfound){
  for(i=100;i<200;i++){
   for(j=i;j<200;j++){
      for(k=j;k<200;k++){
         //..do stuffs.....//
      } 
    }
  }
}
 if(matchnotfound){
  for(i=200;i<300;i++){
   for(j=i;j<300;j++){
      for(k=j;k<300;k++){
         //..do stuffs.....//
      } 
    }
  }
}
 if(matchnotfound){
  for(i=300;i<400;i++){
   for(j=i;j<400;j++){
      for(k=j;k<400;k++){
         //..do stuffs.....//
      } 
    }
  }
}