Java explicit configurable nested loop count
I am trying to do a custom number of nested loops, something like this
int size=4;
for ...
for ...
for ...
for ...
And when resized, create a new nested loop
int size=6;
for ...
for ...
for ...
for ...
for ...
for ...
I tried and tested 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 to create, compile and run an external Java file. Are there better ways to do the same without using an external file?
source to share
Recursion is the answer (as above) or manipulating the "i" variables inside the array:
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;
}
}
source to share
The specific problem you can solve can be solved in several different ways, but here is the general answer.
Usually, when you have a situation where the only way out seems to be writing meta-program
(i.e. code to generate code, often happens to people who start programming), give recursion a thought.
Example
Consider the problem of creating all possible length strings k
that can be created using a set S = {a, b, c, d}
.
One way to do this is to write a metaprogram that generates another program that has k for
loops. Something like:
for `i1` in S:
for `i2` in S:
...
for `ik` in S:
print i1 + i2 + ... + ik
Then you need to compile it and run the executable so obtained using system()
or a similar function.
A simpler alternative is to use recursion.
For example,
//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
printKdigs
in some sense represents a for loop. -
We need a data structure that can hold the state created by each of these activations, in this case it is
string
str
. -
We set the values ββcorrectly and recurse. Finally, on completion, the value in the data structures containing the recursive call trail (
str
here) gives you one legal combination.
source to share