Reputation: 37
I've got a program that will dynamically access different methods and each method will have different amounts of parameters. I need to find a way to permute through thousands of different arrangements of these parameters, and I'm not sure how to loop through these permutations dynamically.
For instance, for a function that has two parameters, I can iterate through the permutations like this:
public static void main(String[] args) {
List<Object[]> params = new ArrayList();
params.add(new Integer[]{1,2,3});
params.add(new Boolean[]{false,true});
runCalculation("function1",params);
}
public void runCalculation(String functionName, List<Object> parameters){
for(Object i : parameters.get(0)){
for(Object j : parameters.get(1)){
//Do reflection function call with (i,j) as parameters
}
}
}
But if I were to have the next function I want to run use 3 parameters, this will no longer iterate through all the permutations. How can I use a dynamic amount of for loops to correctly process a list of arrays containing parameter values? I think recursion is the only way to implement something like this but I'm still struggling to think up a correct solution to this that will correctly allow for a dynamic amount of parameters for each function, and then different types for these parameters.
Upvotes: 2
Views: 195
Reputation: 1911
public void runCalculation(String functionName, List<Object> ... parameters){
for(List<Object> list : parameters)
{
//Do reflection function call with obj as parameter
}
}
its called varargs, also try to use enhanced for - its much easier to use and has very little overhead
Upvotes: 1
Reputation: 6639
Here's how you can do something like that in C: should be easy to convert to Java.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
runCalculation( char * functionName, char * parameters, int numParams )
{
int size = strlen(parameters); // number of parameters to choose from
int i, j;
int indices[numParams];
for (i=0; i < numParams; ++i)
// initialise indices
indices[i] = i;
while (1) {
// output parameters
for (i=0; i < numParams; ++i)
printf("%c", parameters[indices[i]]);
printf("\n");
// now advance j'th parameter
j = numParams - 1;
while(1) {
indices[j]++;
if (indices[j] < size - (numParams-1-j))
// found a combination that 'works'
break;
// can't create a new combination with current j, so try new one
--j;
if (j < 0)
return;
}
// reset everything after indices[j]: they will all be consecutive
for (i=j+1; i < size; ++i)
indices[i] = indices[i-1] + 1;
}
}
main( int argc, char ** argv) {
if (argc != 3) {
printf("need two arguments (string to permute, # of combo elements): bye\n");
exit(1);
}
runCalculation( "testFunction", argv[1], atoi(argv[2]) );
}
Output when ran with input "abcdef" and 4:
abcd
abce
abcf
abde
abdf
abef
acde
acdf
acef
adef
bcde
bcdf
bcef
bdef
cdef
Save the code onto your system, compile it, try various test cases, and once you are convinced that this is what you need, then show me the Java way of writing this. Just so I know. Thank you.
Upvotes: 0
Reputation: 12959
Here is my solution (I didn't know that arrays don't implement Iterable
, and i'm too lazy to change it now since it is based on interators):
public static void print(Object a, Object b, Object c) {
System.out.format("%s, %s, %s\n", a, b, c);
}
public static void runCalculation(Method m, Object instance, List<Iterable<?>> argList)
throws Exception {
int argc = argList.size(); //ARG Count
int depth = 0;
Stack<Iterator<?>> iteratorStack = new Stack<>();
Object[] args = new Object[argc]; //call with these args
boolean fromTop = true; //to know where we come from
while (depth > -1) {
if (fromTop && depth == argc) {
m.invoke(instance, args);
depth--;
fromTop = false;
} else if(fromTop) {
iteratorStack.push(argList.get(depth).iterator());
fromTop = false;
} else if (iteratorStack.peek().hasNext()) {
args[depth] = iteratorStack.peek().next();
depth++;
fromTop = true;
} else {
iteratorStack.pop();
depth--;
fromTop = false;
}
}
}
public static void main(String[] args) throws Exception {
List<Iterable<?>> list = new ArrayList<>();
list.add(Arrays.asList("one", "two"));
list.add(Arrays.asList(3, 4));
list.add(Arrays.asList(true, false));
Method m = NaryProduct.class.getMethod("print", Object.class, Object.class, Object.class);
runCalculation(m, null, list);
}
Output:
one, 3, true
one, 3, false
one, 4, true
one, 4, false
two, 3, true
two, 3, false
two, 4, true
two, 4, false
Upvotes: 0
Reputation: 17
I apologize if i'm not understanding the question, but what about nested for loops?
for(int i = 0; i < params.size(); i++)
{
for(int j = 0; j < params.get(i).size(); j++)
{
}
}
Would this work?
edit: I figured out what algorithm you work looking for and the recursive solution is:
public static String recursive(List<Object[]> params)
{
String result = "";
if(Params.isEmpty())
return result;
Object[] objects = params.remove(0);
for(Object i : objects)
{
result += i.toString();
List<Object[]> newParams = new ArrayList<>(newParams);
result += recursive(newParams);
}
return result;
}
Upvotes: 0
Reputation: 11030
I think what you are trying here is reflection. You just need to read the API and use the appropriate methods. Note that you will need to know which class you want to invoke the method name on. Java won't look through all methods in all classes for you.
public void runCalculation(String functionName, List<Object> parameters)
throws NoSuchMethodException
{
Class<?>[] typeSignature = new Class<?>[ parameters.size() ];
for( int i = 0; i < parameters.size(); i++ ) {
typeSignature[i] = parameters.get( i ).getClass();
}
Class<?> type = this.getClass(); // substitute with desired class
Method m = type.getMethod(functionName, typeSignature);
// do stuff with 'm' here (like invoke it)
}
Upvotes: 0