【问题标题】:Dynamic amount of loops through permutations通过排列的动态循环量
【发布时间】:2014-09-16 15:25:23
【问题描述】:

我有一个程序可以动态访问不同的方法,每个方法都有不同数量的参数。我需要找到一种方法来排列这些参数的数千种不同排列,但我不确定如何动态循环这些排列。

例如,对于一个有两个参数的函数,我可以像这样遍历排列:

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
        }
    }
}

但是,如果我要让下一个要运行的函数使用 3 个参数,这将不再遍历所有排列。如何使用动态数量的 for 循环来正确处理包含参数值的数组列表?我认为递归是实现此类事情的唯一方法,但我仍在努力想出一个正确的解决方案,该解决方案将正确地为每个函数提供动态数量的参数,然后为这些参数提供不同的类型。

【问题讨论】:

  • 也许您需要递归而不是 for 循环?
  • 你想要的不是permutation,而是cartesian productn-ary product(我会尽快添加答案)

标签: java arrays list recursion


【解决方案1】:
public void runCalculation(String functionName, List<Object> ... parameters){

    for(List<Object> list : parameters)
    {
         //Do reflection function call with obj as parameter
    }
}

它被称为varargs,也可以尝试使用enhanced for - 它更容易使用并且开销很小

【讨论】:

  • 这解决不了任何问题...我已经很清楚反射并在原始问题中引用了它。这甚至不起作用,因为参数中的每个对象都是一个参数数组,而不是数组中需要传递给函数的单个项目。你完全误解了这个问题。
  • 这根本没有任何意义——我认为你需要回到基础,从头开始学习 java。但是你在一个方面是对的,虽然你甚至不知道:我在循环中有一个错字,现在已经修复了。
  • 你是一个误解了这个问题的人。此后,我使用递归调用实现了笛卡尔积函数,解决了这个问题。它接受任意数量的对象参数,并返回笛卡尔积,导致输入参数 {1,2,3},{false,true} 输出 {1,false}{1,true}{2,false} 等,在一个列表中。在告诉某人“回到基础”之前,因为您不了解某些内容,也许可以重新阅读该问题以尝试查看您的困惑的答案是否一直存在。
【解决方案2】:

如果我不理解这个问题,我深表歉意,但是嵌套的 for 循环呢?

for(int i = 0; i < params.size(); i++)
{
  for(int j = 0; j < params.get(i).size(); j++)
  {
  }
}

这行得通吗?

编辑: 我弄清楚了你在寻找什么算法,递归解决方案是:

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;
}

【讨论】:

    【解决方案3】:

    我认为您在这里尝试的是反射。您只需要阅读 API 并使用适当的方法。请注意,您需要知道要在哪个类上调用方法名称。 Java 不会为您查看所有类中的所有方法。

       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)
    
       }
    

    【讨论】:

      【解决方案4】:

      这是我的解决方案(我不知道数组没有实现Iterable,我现在懒得更改它,因为它是基于交互器的):

      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);
      }
      

      输出:

      one, 3, true
      one, 3, false
      one, 4, true
      one, 4, false
      two, 3, true
      two, 3, false
      two, 4, true
      two, 4, false
      

      【讨论】:

        【解决方案5】:

        以下是在 C 中执行类似操作的方法:应该很容易转换为 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]) );
        
        }
        

        使用输入“abcdef”和 4 运行时的输出:

        abcd
        abce
        abcf
        abde
        abdf
        abef
        acde
        acdf
        acef
        adef
        bcde
        bcdf
        bcef
        bdef
        cdef
        

        将代码保存到您的系统中,编译它,尝试各种测试用例,一旦您确信这是您需要的,然后向我展示 Java 编写此代码的方式。就这样我知道。谢谢。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-03-19
          • 2011-07-24
          • 1970-01-01
          • 2015-08-12
          相关资源
          最近更新 更多