简体   繁体   English

如何编写大量的 for 循环

[英]how can I program a large number of for loops

I'm new to programming so I'm sorry in phrasing if I'm not asking this question correctly.我是编程新手,所以如果我没有正确提出这个问题,我很抱歉。

I have the following code:我有以下代码:

int sum = 100;
int a1 = 20;
int a2 = 5;
int a3 = 10;
for (int i = 0; i * a1 <= sum; i++) {
    for (int j = 0; i * a1 + j * a2 <= sum; j++) {
        for (int k = 0; i * a1 + j * a2 + k * a3 <= sum; k++) {
            if (i * a1 + j * a2 + k * a3 == sum) {
                System.out.println(i + "," + j + "," + k);
            }
        }
    }   
}

basically what it does is tell me the different combinations of a1 , a2 , and a3 that equal the above sum (in this case 100).基本上它的作用是告诉我a1a2a3的不同组合,它们等于上述总和(在本例中为 100)。 This works fine but I'm trying to apply it to a larger dataset now and I'm not sure how to do without manually programming the for loops or knowing in advanced how many variables I'll have(could be anywhere from 10 to 6000).这工作正常,但我现在正试图将它应用到更大的数据集,我不确定如何不手动编程 for 循环或提前知道我将拥有多少个变量(可能从 10 到 6000 )。 I basically have a sql query that loads that data from an array.我基本上有一个从数组加载数据的 sql 查询。

Is there a way in Java OR python (I'm learning both) to automatically create nested for and if loops? Java 或 python (我都在学习)有没有办法自动创建嵌套forif循环?

Thanks so much in advance.提前非常感谢。

Recursion.递归。

This is what it sounds like you are trying to solve:这听起来像是您要解决的问题:

your current example: 20x 1 + 5x 2 + 10x 3 = 100您当前的示例:20x 1 + 5x 2 + 10x 3 = 100

so in general you are doing: A 1 x 1 + A 2 x 2 +... + A n x n = SUM所以一般来说你在做:A 1 x 1 + A 2 x 2 +... + A n x n = SUM

so you pass in an array of constants {A 1 , A 2 , ..., A n } and you want to solve for {x 1 , x 2 , ..., x n }所以你传入一个常量数组 {A 1 , A 2 , ..., A n } 并且你想解决 {x 1 , x 2 , ..., x n }

    public void findVariables(int[] constants, int sum, 
                              int[] variables, int n, int result) {
        if (n == constants.length) { //your end condition for the recursion
            if (result == sum) {
                printArrayAsList(variables);
            }
        } else if (result <= sum){ //keep going
            for (int i = 0; result + constants[n]*i <= sum; i++) {
                variables[n] = i;
                findVariables(constants, sum, variables, n+1, result+constants[n]*i);
            }
        }
    }

and to call for your example you'd use:并调用您的示例,您将使用:

    findVariables(new int[] {20, 5, 20}, 100, new int[] {0,0,0}, 0, 0)

Although it may not scale, here's a really simple brute-force python solution that doesn't require recursion:尽管它可能无法扩展,但这是一个非常简单的蛮力 python 解决方案,不需要递归:

import itertools
target_sum = 100
a = 20
b = 5
c = 10
a_range = range(0, target_sum + 1, a)
b_range = range(0, target_sum + 1, b)
c_range = range(0, target_sum + 1, c)
for i, j, k in itertools.product(a_range, b_range, c_range):
    if i + j + k == 100:
        print i, ',', j, ',', k

Also, there are ways to compute the cartesian product of an arbitrary list of lists without recursion.此外,还有一些方法可以计算任意列表的笛卡尔积而无需递归。 ( lol = list of lists) lol =列表列表)

def product_gen(*lol):
    indices = [0] * len(lol)
    index_limits = [len(l) - 1 for l in lol]
    while indices < index_limits:
        yield [l[i] for l, i in zip(lol, indices)]
        for n, index in enumerate(indices):
            index += 1
            if index > index_limits[n]:
                indices[n] = 0
            else:
                indices[n] = index
                break
    yield [l[i] for l, i in zip(lol, indices)]

If you're just learning python, then you might not be familiar with the yield statement or the zip function;如果您只是学习 python,那么您可能不熟悉yield语句或zip function; in that case, the below code will be clearer.在这种情况下,下面的代码会更清晰。

def product(*lol):
    indices = [0] * len(lol)
    index_limits = [len(l) - 1 for l in lol]
    index_accumulator = []
    while indices < index_limits:
        index_accumulator.append([lol[i][indices[i]] for i in range(len(lol))])
        for n, index in enumerate(indices):
            index += 1
            if index > index_limits[n]:
                indices[n] = 0
            else:
                indices[n] = index
                break
    index_accumulator.append([lol[i][indices[i]] for i in range(len(lol))])
    return index_accumulator

You did a smart thing in your code by skipping those values for which i + j + k is greater than sum .通过跳过那些i + j + k大于sum的值,您在代码中做了一件聪明的事。 None of these do that.这些都没有这样做。 But it's possible to modify the second two to do that, with some loss of generality.但是可以修改后两个来做到这一点,但会失去一般性。

With Java, some generic simplistic implementation would require at least two classes:使用 Java,一些通用的简单实现将需要至少两个类:

Some delegate to pass to the recursive algorithm, so you can receive updates wherever the execution is at.一些委托传递给递归算法,因此无论执行在哪里,您都可以接收更新。 Something like:就像是:

public interface IDelegate {
   public void found(List<CombinationFinder.FoundElement> nstack);
}

The for implementation, something like: for实现,例如:

public class CombinationFinder {
   private CombinationFinder next;
   private int multiplier;

   public CombinationFinder(int multiplier) {
      this(multiplier, null);
   }
   public CombinationFinder(int multiplier, CombinationFinder next) {
      this.multiplier = multiplier;
      this.next = next;
   }

   public void setNext(CombinationFinder next) {
      this.next = next;
   }

   public CombinationFinder getNext() {
      return next;
   }

   public void search(int max, IDelegate d) {
      Stack<FoundElement> stack = new Stack<FoundElement>();
      this.search(0, max, stack, d);
   }

   private void search(int start, int max, Stack<FoundElement> s, IDelegate d) {
      for (int i=0, val; (val = start + (i*multiplier)) <= max; i++) {
         s.push(i);
         if (null != next) {
            next.search(val, max, s, d);
         } else if (val == max) {
            d.found(s);
         } 
         s.pop();
      }
   } 

   static public class FoundElement {
      private int value;
      private int multiplier;
      public FoundElement(int value, int multiplier) {
         this.value = value;
         this.multiplier = multiplier;
      }
      public int getValue() {
         return value;
      }
      public int getMultiplier() {
         return multiplier;
      }
      public String toString() {
         return value+"*"+multiplier;
      }
   }
}

And finally, to setup and run (test):最后,设置和运行(测试):

CombinationFinder a1 = new CombinationFinder(20);
CombinationFinder a2 = new CombinationFinder(5);
CombinationFinder a3 = new CombinationFinder(10);

a1.setNext(a2);
a2.setNext(a3);

a1.search(100, new IDelegate() {
   int count = 1;
   @Override
   public void found(List<CombinationFinder.FoundElement> nstack) {
      System.out.print("#" + (count++) + " Found : ");
      for (int i=0; i<nstack.size(); i++) {
         if (i>0) System.out.print(" + ");
            System.out.print(nstack.get(i));
         }
         System.out.println();
      }
   }
});

Will output 36 solutions.将output 36个解决方案。

With this concept, you can have as many inner loops as you want, and even customize each one if you want through inheritance.有了这个概念,您可以拥有任意数量的内部循环,甚至可以通过 inheritance 自定义每个内部循环。 You can even reuse objects (ie: a1.setNext(a1); ) with no problem at all.您甚至可以毫无问题地重用对象(即: a1.setNext(a1); )。

** UPDATE ** **更新**

Simply because I like monty 's solution , I couldn't resist into testing it, and here's the result, tweaked a little.仅仅因为我喜欢monty解决方案,我无法抗拒对其进行测试,这就是结果,稍微调整了一下。

DISCLAIMER all credits goes to monty for the algorithm免责声明所有学分归于算法的蒙蒂

public class PolynomialSolver {

   private SolverResult delegate;
   private int min = 0;
   private int max = Integer.MAX_VALUE;

   public PolynomialSolver(SolverResult delegate) {
      this.delegate = delegate;
   }

   public SolverResult getDelegate() {
      return delegate;
   }

   public int getMax() {
      return max;
   }

   public int getMin() {
      return min;
   }

   public void setRange(int min, int max) {
      this.min = min;
      this.max = max;
   }

   public void solve(int[] constants, int total) {
      solveImpl(constants, new int[constants.length], total, 0, 0);
   }

   private void solveImpl(int[] c, int[] v, int t, int n, int r) {
      if (n == c.length) { //your end condition for the recursion
         if (r == t) {
            delegate.solution(c, v, t);
         }
      } else if (r <= t){ //keep going
         for (int i=min, j; (i<=max) && ((j=r+c[n]*i)<=t); i++) {
            v[n] = i;
            solveImpl(c, v, t, n+1, j);
         }
      }
   }

   static public interface SolverResult {
      public void solution(int[] constants, int[] variables, int total);
   }

   static public void main(String...args) {

      PolynomialSolver solver = new PolynomialSolver(new SolverResult() {
         int count = 1;
         @Override
         public void solution(int[] constants, int[] variables, int total) {
            System.out.print("#"+(count++)+" Found : ");
            for (int i=0, len=constants.length; i<len; i++) {
               if (i>0) System.out.print(" + ");
               System.out.print(constants[i]+"*"+variables[i]);
            }
            System.out.println(" = " + total);
         }
      });

      // test some constants = total
      solver.setRange(-10, 20);
      solver.solve(new int[] {20, 5, 10}, 100); // will output 162 solutions

   }
}

There may be a way to put the variables into a List and use recursion to eliminate all of the loops.可能有一种方法可以将变量放入 List 并使用递归来消除所有循环。 However, the running time of this brute force approach grows exponentially with the number of variables.然而,这种蛮力方法的运行时间随着变量的数量呈指数增长。 (ie the algorithm may not complete in our lifetimes for numbers of variables in the thousands). (即,对于成千上万的变量,该算法可能无法在我们有生之年完成)。

There are some articles on how to solve Diophantine equations more efficiently.有一些关于如何更有效地求解丢番图方程的文章。 Number theory is not my area of expertise, but hopefully these will be of assistance.数论不是我的专业领域,但希望这些会有所帮助。

http://www.wikihow.com/Solve-a-Linear-Diophantine-Equation http://www.wikihow.com/Solve-a-Linear-Diophantine-Equation

Based on @monty's solution but with a few tweaks.基于@monty 的解决方案,但有一些调整。 The last constant can be determined by division.最后一个常数可以通过除法确定。

public static void findVariables(int[] constants, int sum) {
    findVariables0(constants, sum, new int[constants.length], 0);
}

private static void findVariables0(int[] constants, int remaining, int[] variables, int n) {
    if(n == constants.length - 1) {
        // solution if the remaining is divisible by the last constant.
        if (remaining % constants[n] == 0) {
            variables[n] = remaining/constants[n];
            System.out.println(Arrays.toString(variables));
        }
    } else {
        for (int i = 0, limit = remaining/constants[n]; i <= limit; i++) {
            variables[n] = i;
            findVariables0(constants, remaining - i * constants[n], variables, n+1);
        }
    }
}

public static void main(String... args) {
    findVariables(new int[] { 5,3,2 }, 100);
}

When I changed int to double I wouldn't use float for 99% of cases due to the rounding error you get is not worth the memory you save.当我将int更改为double时,我不会在 99% 的情况下使用float ,因为您得到的舍入误差不值得您保存的 memory。

public static void findVariables(double[] constants, double sum) {
    findVariables0(constants, sum, new double[constants.length], 0);
}

private static void findVariables0(double[] constants, double remaining, double[] variables, int n) {
    if(n == constants.length - 1) {
        // solution if the remaining is divisible by the last constant.
        if (remaining % constants[n] == 0) {
            variables[n] = remaining/constants[n];
            System.out.println(Arrays.toString(variables));
        }
    } else {
        for (int i = 0, limit = (int) (remaining/constants[n]); i <= limit; i++) {
            variables[n] = i;
            findVariables0(constants, remaining - i * constants[n], variables, n+1);
        }
    }
}

public static void main(String... args) {
    findVariables(new double[]{5.5, 3, 2}, 100);
}

This compiles and runs fine.这编译并运行良好。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何使用“for”循环运行此程序 - How Can I run this program by using “for” loops 如何使用For循环减少以下代码中的行数? - How can I use For loops to reduce the number of lines in the following code? 如何编程检查数字是否为Zeisel数字? - How can I program to check whether a number is a zeisel number or not? 如何阅读Java程序的大量短信? - How to read Large number of SMSs by Java program? 如何在Java中以字符串格式计算大量的模数 - How can I calculate modulo of a large number in String format in java 如何将大量的Stringtemplate文件组织到不同的文件夹中 - How can I organize a large number of Stringtemplate files into different folders 每次程序循环时如何创建新对象? - How can I create a new object every time my program loops? 如何使用for循环交换Java中数字的第一个和最后一个数字? - How can I swap the first and last digits of a number in Java using for for-loops? 100个循环完成后如何获得比较的总数? - How can I get the total number of comparisons after the 100 loops have finished? 如何在一定数量的循环后停止 Java 中带有 If 语句的 While 循环? - How Can I get a While loop with an If statement in Java to stop after a certain number of loops?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM