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 ?
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;
}
}
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);
}
}
Each activation of printKdigs represents a for loop in some sense.
We need a data structure that can hold the state created by each of these activations, in this case, it is the string str.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With