Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java customizable amount of nested for loops

Tags:

java

for-loop

I'm trying to make a customizable amount of nested for loops, something like this

int size=4;
for ...
  for ...
    for ...
      for ...

And when changing the size, creating a new nested loop

int size=6;
for ...
  for ...
    for ...
      for ...
        for ...
          for ...

I've been trying and testing and finally I got this:

    // The amount of nested loops
    int size=3;

    // Variables
    String output="";
    String code="";
    String home=new File("").getAbsolutePath();

    // Generating code

    // Opening
    code+="public class Temp { \n";
    code+="    public static void main(String[] args) { \n";

    String depth="        ";

    // Making the variables
    code+=depth+"int[] data = new int["+size+"];\n";
    code+=depth+"String output = \"\";\n";

    // Making the for loops
    for(int i=0; i<size; i++) {
        // Adding formatting
        for(int x=i; x>0; x--)
            code+="    ";

        // Creating for-loop
        code+=depth+"for (data["+i+"]=0; data["+i+"]<10; data["+i+"]++) {\n";
    }

    // Adding formatting
    for(int x=0; x<size; x++)
        code+="    ";

    // Making the output (data[0]+""+data[1]+""+data[2]+"" etc)
    code+=depth+"output+=";
    for(int i=0; i<size; i++) {
        code+="data["+i+"]+\"\"";
        if(i<size-1)
            code+="+";
    }
    code+=";\n";

    // Adding formatting
    for(int x=0; x<size; x++)
        code+="    ";

    // Adding a newline after the output
    code+=depth+"output+=\"\\n\";\n";

    // Adding formatting and closing for-loops
    for(int i=0; i<size; i++) {
        for(int x=i; x<size-1; x++)
            code+="    ";
        code+=depth+"}\n";
    }

    // Outputting the variable output
    code+=depth+"System.out.println(output);\n";
    code+="    }\n";
    code+="}\n";

    // Outputting the code (for debugging purposes)
    System.out.println(code);

    // Compiling, running and getting output
    try {
        // Making a file called Temp.java
        FileOutputStream fos=new FileOutputStream("Temp.java");
        byte[] buf=code.getBytes();
        fos.write(buf);
        fos.close();

        System.out.println("===== ===== ===== ===== ===== =====");
        System.out.println("\n=====        Compiling        =====\n");

        // Executing
        Process p=Runtime.getRuntime().exec("javac -d "+home+" Temp.java");

        // Getting output and error
        InputStream is=p.getInputStream();
        InputStream es=p.getErrorStream();

        buf=new byte[8192];
        byte[] ebuf=new byte[8192];

        is.read(buf);
        es.read(ebuf);

        System.out.println(new String(buf).trim());
        System.err.println(new String(ebuf).trim());

        System.out.println("\n=====         Running         =====");

        // Executing
        p=Runtime.getRuntime().exec("java Temp");

        // Getting output and error
        is=p.getInputStream();
        es=p.getErrorStream();

         buf=new byte[8192];
        ebuf=new byte[8192];
        is.read(buf);
        es.read(ebuf);

        // Make output the value of the external 'output'
        output=new String(buf).trim();
        System.err.println(new String(ebuf).trim());

        System.out.println("\n=====   Removing temp files   =====");

        // Executing
        p=Runtime.getRuntime().exec("rm -f Temp.java Temp.class");

        // Getting output and error
        is=p.getInputStream();
        es=p.getErrorStream();

        buf=new byte[8192];
        ebuf=new byte[8192];
        is.read(buf);
        es.read(ebuf);

        System.out.println(new String(buf).trim());
        System.err.println(new String(ebuf).trim());

        System.out.println("\n===== ===== ===== ===== ===== =====");

    } catch(Exception e) {
        e.printStackTrace();
    }

    // Outputting the output
    System.out.println("output\n"+output);

It works as it should, but I hate the way of creating, compiling and running an external Java file. Are there any better ways to do the same thing, without the use of an external file ?

like image 323
Charlie Avatar asked Mar 25 '26 07:03

Charlie


2 Answers

Either recursion is the answer (as stated above), or managing your "i" variables within an array instead:

public void nestedLoop(int size, int loopSize) {
    int[] i = new int[size];
    while (i[size-1] < loopSize) {
       doSomethingWith(i);
       increment(i, loopSize);
    }
}

public void increment(int[] i, int maxSize) {
   int idx = 0;
   while (idx < i.length) {
      if (++i[idx] < maxSize) {
         return;
      }
      i[idx++] = 0;
   }
}
like image 62
Daniel Avatar answered Mar 27 '26 21:03

Daniel


The specific problem you have might be solved in several different ways, what follows is a generic answer.

Usually, whenever you have a situation in which the only way out seems to be writing a meta-program (i.e. code to generate code, happens frequently with people who are beginning programming), give recursion a thought.

Example


Consider the problem of generating all the possible strings of length k that can be created using the set S = {a, b, c, d}.

One way of doing it is to write a meta program, which generates another program having k for loops. Something like:

for `i1` in S:
    for `i2` in S:
    ...
       for `ik` in S:
           print i1 + i2 + ... + ik

You will then need to compile it and run the executable thus obtained using system() or a similar function.

A much cleaner alternative is to use recursion.

For eg:

//sg
public class printKStr
{
    int k;
    String S;
    public void printKdigs(int pos, char[] str) {
        if(pos == k) {
            System.out.println(str);
            return;
        }
        int l = S.length();
        for(int i = 0; i < l; i++) {
            str[pos] = S.charAt(i);
            printKdigs(pos + 1, str);
        }
    }

    public static void main(String args[]) {
        printKStr pk = new printKStr();
        pk.S = "abc";
        pk.k = 3;
        char[] temp1 = new char[pk.k + 1];
        pk.printKdigs(0, temp1);
    }

}
  1. Each activation of printKdigs represents a for loop in some sense.

  2. We need a data structure that can hold the state created by each of these activations, in this case, it is the string str.

  3. We set values correctly and recurse. Finally, at the termination, the value in the data structures holding the trail of recursive calls (str here) gives you one legal combination.

like image 42
axiom Avatar answered Mar 27 '26 21:03

axiom