I have a pool of options in groups and I'm trying to dynamically generate the combinations for testing purposes. I would like to define the buckets and have code generating all the combinations to be fed to my TestNG test via #DataProvider. Right now I have some cases hardcoded but it's obvious is not the best way of doing it for maintaining the code.
I'm struggling to handle the case where you have x "balls" in y "buckets" when y is > 2.
In the trivial case let's say you have the following example:
public static void main(String [] args){
Object[][] combinations = getCombinations(
new String[]
{
"1", "2"
},
new String[]
{
"3", "4"
}/*,
new String[]
{
"5", "6"
}*/);
for (Object[] combination : combinations)
{
System.out.println(Arrays.toString(combination));
}
}
private Object[][] getCombinations(Object[]... arrays)
{
if (arrays.length == 0)
{
return new Object[0][0];
}
List<Object[]> solutions = new ArrayList<>();
Object[] array1 = arrays[0];
for (Object o : array1)
{
for (int i = 1; i < arrays.length; i++)
{
for (Object o2 : arrays[i])
{
int count = 0;
Object[] path = new Object[arrays.length];
path[count++] = o;
path[count++] = o2;
solutions.add(path);
}
}
}
return solutions.toArray(new Object[0][0]);
}
Output:
[1, 3]
[1, 4]
[2, 3]
[2, 4]
Adding the third "bucket" throws everything out the window.
The solutions would be as follows:
[1,3,5]
[1,3,6]
[1,4,5]
[1,4,6]
[2,3,5]
[2,3,6]
[2,4,5]
[2,4,6]
Any ideas how to attack this issue? Ideally you would pass getCombinations the amount of picks per bucket.
Although a solution code would be welcomed, I'm more interested in the reasoning behind it.
Update
For future visitors here's the great answer by Kevin Anderson in a generic form:
Unit Test:
import static org.testng.Assert.assertEquals;
import java.util.Arrays;
import java.util.List;
import org.testng.annotations.Test;
public class CombinationNGTest
{
#Test
public void testCombinaitonOnePick()
{
List<List<Integer>> result
= Combination.pickKfromEach((List<List<Integer>>) Arrays.asList(
Arrays.asList(1, 2),
Arrays.asList(3, 4)),
1);
assertEquals(result.size(), 4, result.toString());
result = Combination.pickKfromEach((List<List<Integer>>) Arrays.asList(
Arrays.asList(1, 2),
Arrays.asList(3, 4),
Arrays.asList(5, 6)),
1);
assertEquals(result.size(), 8, result.toString());
result = Combination.pickKfromEach((List<List<Integer>>) Arrays.asList(
Arrays.asList(1, 2),
Arrays.asList(3, 4),
Arrays.asList(5, 6),
Arrays.asList(7, 8)),
1);
assertEquals(result.size(), 16, result.toString());
List<List<String>> result2= Combination.pickKfromEach((List<List<String>>) Arrays.asList(
Arrays.asList("A", "B"),
Arrays.asList("C", "D")),
1);
assertEquals(result2.size(), 4, result.toString());
}
#Test
public void testCombinaitonMultiplePicks()
{
List<List<Integer>> result
= Combination.pickKfromEach((List<List<Integer>>) Arrays.asList(
Arrays.asList(1, 2, 3),
Arrays.asList(4, 5, 6)),
2);
assertEquals(result.size(), 9, result.toString());
}
}
You've hit on an overly complicated solution which, nonetheless, just happens to work for the case of two buckets. However, as you have discovered, it won't extend naturally to three or more buckets.
Here's a simpler solution for the two-bucket case, generified and using Lists in place of arrays:
// Find all 2-item combinations consisting of 1 item picked from
// each of 2 buckets
static <T> List<List<T>> pick1From2(List<List<T>> in)
{
List<List<T>> result = new ArrayList<>();
for (int i = 0; i < in.get(0).size(); ++i) {
for (int j = 0; j < in.get(1).size(); ++j) {
result.add(Arrays.asList(in.get(0).get(i), in.get(1).get(j)));
}
}
return result;
}
The outer loop runs over all the elements of the first bucket and for each element of the first bucket, the inner loop runs over the elements of the second bucket.
For three buckets, you can just add a third level of loop nesting:
// Find all 3-item combinations consisting of 1 item picked from
// each of 3 buckets
static <T> List<List<T>> pick1From3(List<List<T>> in)
{
List<List<T>> result = new ArrayList<>();
for (int i = 0; i < in.get(0).size(); ++i) {
for (int j = 0; j < in.get(1).size(); ++j) {
for (int k = 0; k < in.get(2).size(); ++k)
result.add(Arrays.asList(in.get(0).get(i), in.get(1).get(j), in.get(2).get(k)));
}
}
return result;
}
Now you have the outer loop stepping through the items of the first bucket, an intermediate loop stepping through the items of the second bucket, and an innermost loop stepping over the elements of the third bucket.
But this approach is limited by the fact that the depth of loop nesting needed is directly related to the number of buckets to be processed: Sure, you can add a fourth, a fifth, etc., level of loop nesting to handle four, five, or more buckets. However, the basic problem remains: you have to keep modifying the code to accommodate ever-increasing numbers of buckets.
The solution to the dilemma is a single algorithm which accommodate any number, N, of buckets by effectively simulating for loops nested to N levels. An array of N indices will take the place of the N loop control variables of N nested for statements:
// Find all `N`-item combinations consisting 1 item picked from
// each of an `N` buckets
static <T> List<List<T>> pick1fromN(List<List<T>> s)
{
List<List<T>> result = new ArrayList<>();
int[] idx = new int[s.size()];
while (idx[0] < s.get(0).size()) {
List<T> pick = new ArrayList(s.size());
for (int i = 0; i < idx.length; ++i) {
pick.add(s.get(i).get(idx[i]));
}
result.add(pick);
int i = idx.length - 1;
while (++idx[i] >= s.get(i).size() && i > 0) {
idx[i] = 0;
--i;
}
}
return result;
}
The indices all start off at zero, and each maxxes out upon reaching the size of the corresponding bucket. To step to the next combination (inner while loop) the last index index is incremented; if it has maxxed out, it is reset to zero and the next higher index is incremented. If the next higher index also maxes out, it resets and causes the next index to increment, and so on. idx[0] never resets after it increments, so that the outer while can detect when idx[0] has maxxed out.
Picking k items from each bucket is basically the same process, except with the sets of k-combinations of the buckets substituted for the original buckets:
// Find all `N * k`-item combinations formed by picking `k` items
// from each of `N` buckets
static <T> List<List<T>> pickKfromEach(List<List<T>> sets, int k)
{
List<List<List<T>>> kCombos = new ArrayList<>(sets.size());
for (List<T> ms : sets) {
kCombos.add(combinations(ms, k));
}
ArrayList<List<T>> result = new ArrayList<>();
int[] indices = new int[kCombos.size()];
while (indices[0] < kCombos.get(0).size()) {
List<T> pick = new ArrayList<>(kCombos.size());
for (int i = 0; i < indices.length; ++i) {
pick.addAll(kCombos.get(i).get(indices[i]));
}
result.add(pick);
int i = indices.length - 1;
while (++indices[i] >= kCombos.get(i).size() && i > 0) {
indices[i] = 0;
--i;
}
}
return result;
}
static <T> List<List<T>> combinations(List<T> s, int k) throws IllegalArgumentException
{
if (k < 0 || k > s.size()) {
throw new IllegalArgumentException("Can't pick " + k
+ " from set of size " + s.size());
}
List<List<T>> res = new LinkedList<>();
if (k > 0) {
int idx[] = new int[k];
for (int ix = 0; ix < idx.length; ++ix) {
idx[ix] = ix;
}
while (idx[0] <= s.size() - k) {
List<T> combo = new ArrayList<>(k);
for (int ix = 0; ix < idx.length; ++ix) {
combo.add(s.get(idx[ix]));
}
res.add(combo);
int ix = idx.length - 1;
while (ix > 0 && (idx[ix] == s.size() - k + ix))
--ix;
++idx[ix];
while (++ix < idx.length)
idx[ix] = idx[ix-1]+1;
}
}
return res;
}
Like the pick routine, the combinations method uses an array of indices to enumerate the combinations. But the indices are managed a bit differently. The indices start out at {0, 1, 2, ..., k-1_}, and they max-out when they have reached the values {n - k, n - k + 1, ..., n}. To step to the next combination, last index which has not yet maxed-out is incremented, and then each following index is reset to the value of the one above it, plus one.
The Problem you are struggling with can not easily be solved iteratively, since the complexity changes with the amount of given Arrays.
A solution to this problem is the use of a recursive function that generates the Permutations of the first Argument and all the following Arrays.
Unfortunately i can't write any fully working code right now, but i can try to give you an example:
public static Object[] permuteAll(Object[] objs1, Object[][] objs2) {
if(objs2.length == 1){
return permuteAll(objs1, objs2);
}else{
return permuteAll(objs2[0], objs2[/*The rest of the objs[][]*/]]);
}
}
public static Object[] permuteAll(Object[] objs1, Object[] objs2) {
return ... //Your Code for 2 buckets goes here
}
I would also recommend using Generics instead of the Object class, but depending on the way you combine your objects you might not get any real benefit out of this...
Please read the question before marking it as duplicate
I have written following code to remove duplicates from array without using Util classes but now I am stuck
public class RemoveDups{
public static void main(String[] args) {
int[] a = { 1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6, 3, 1, 4, 52, 1, 45, };
int temp;
for (int i : a) {
for (int j = 0; j < a.length - 1; j++) {
if (a[j] > a[j + 1]) {
temp = a[j];
a[j] = a[j + 1];
a[j + 1] = temp;
}
}
}
a = removeDups(a);
for (int i : a) {
System.out.println(i);
}
}
private static int[] removeDups(int[] a) {
int[] result = new int[a.length];
int j = 0;
for (int i : a) {
if (!isExist(result, i)) {
result[j++] = i;
}
}
return result;
}
private static boolean isExist(int[] result, int i) {
for (int j : result) {
if (j == i) {
return true;
}
}
return false;
}
}
and now the output is
1
2
3
4
5
6
45
52
0
0
0
0
0
0
0
0
0
0
Here my problem is
My code is not working in case of 0s
I am not able to understand how sorting an array can reduce time of execution
Is there any way to remove elements from array without using Util classes I know one way to remove convert array into list and then remove but for that also we need Util classes is there any way to implement by myself.
Since the numbers you deal with are limited to a small range you can remove duplicates by a simple "counting sort": mark the numbers you have found in a set-like data structure and then go over the data structure. An array of boolean works just fine, for less memory usage you could create a basic bitset or hash table. If n is the number of elements in the array and m is the size of the range, this algorithm will have O(n+m) complexity.
private static int[] removeDups(int[] a, int maxA) {
boolean[] present = new boolean[maxA+1];
int countUnique = 0;
for (int i : a) {
if (!present[i]) {
countUnique++;
present[i] = true;
}
}
int[] result = new int[countUnique];
int j = 0;
for (int i=0; i<present.length; i++) {
if (present[i]) result[j++] = i;
}
return result;
}
I am not able to understand how sorting an array can reduce time of execution
In a sorted array you can detect duplicates in a single scan, taking O(n) time. Since sorting is faster than checking each pair - O(n log n) compared to O(n²) time complexity - it would be faster to sort the array instead of using the naive algorithm.
As you are making the result array of the same length as array a
so even if you put only unique items in it, rest of the blank items will have the duplicate values in them which is 0 for int array.
Sorting will not help you much, as you code is searching the whole array again and again for the duplicates. You need to change your logic for it.
You can put some negative value like -1 for all the array items first in result array and then you can easily create a new result array say finalResult array from it by removing all the negative values from it, It will also help you to remove all the zeroes.
In java , arrays are of fixed length. Once created, their size can't be changed.
So you created an array of size18.
Then after you applied your logic , some elements got deleted. But array size won't change. So even though there are only 8 elements after the duplicate removal, the rest 10 elements will be auto-filled with 0 to keep the size at 18.
Solution ?
Store the new list in another array whose size is 8 ( or whatever, calculate how big the new array should be)
Keep a new variable to point to the end of the last valid element, in this case the index of 52. Mind you the array will still have the 0 values, you just won't use them.
I am not able to understand how sorting an array can reduce time of execution
What ? You sort an array if you need it to be sorted. Nothing else. Some algorithm may require the array to be sorted or may work better if the array is sorted. Depends on where you are using the array. In your case, the sorting will not help.
As for your final question , you can definitely implement your own duplicate removal by searching if an element exists more than once and then deleting all the duplicates.
My code is not working in case of 0
There were no zeroes to begin with in your array. But because its an int[], after the duplicates are removed the remaining of the indexes are filled with 0. That's why you can see a lot of zeroes in your array. To get rid of those 0s, you need to create another array with a lesser size(size should be equal to the no. of unique numbers you've in your array, excluding 0).
If you can sort your array(I see that its already sorted), then you could either bring all the zeroes to the front or push them to the last. Based on that, you can iterate the array and get the index from where the actual values start in the array. And, then you could use Arrays.copyOfRange(array, from, to) to create a copy of the array only with the required elements.
try this
package naveed.workingfiles;
public class RemoveDups {
public static void main(String[] args) {
int[] a = { 1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6, 3, 1, 4, 52, 1, 45, };
removeDups(a);
}
private static void removeDups(int[] a) {
int[] result = new int[a.length];
int j = 0;
int count = 0;
for (int i : a) {
if (!isExist(result, i)) {
result[j++] = i;
count++;
}
}
System.out.println(count + "_____________");
for (int i=0;i<count;i++) {
System.out.println(result[i]);
}
// return result;
}
private static boolean isExist(int[] result, int i) {
for (int j : result) {
if (j == i) {
return true;
}
}
return false;
}
}
public class RemoveDups {
public static void main(String[] args) {
int[] a = { 1, 2, 0, 3, 1,0, 3, 6, 2};
removeDups(a);
}
private static void removeDups(int[] a) {
int[] result = new int[a.length];
int j = 0;
int count = 0;
boolean zeroExist = false;
for (int i : a) {
if(i==0 && !zeroExist){
result[j++] = i;
zeroExist = true;
count++;
}
if (!isExist(result, i)) {
result[j++] = i;
count++;
}
}
System.out.println(count + "_____________");
for (int i=0;i<count;i++) {
System.out.println(result[i]);
}
// return result;
}
private static boolean isExist(int[] result, int i) {
for (int j : result) {
if (j == i) {
return true;
}
}
return false;
}
}
// It works even Array contains 'Zero'
class Lab2 {
public static void main(String[] args) {
int[] a = { 1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6, 3, 1, 4, 52, 1, 45 };
removeDups(a);
}
private static void removeDups(int[] a) {
int[] result = new int[a.length];
int j = 0;
int count = 0;
for (int i : a) {
if (!isExist(result, i)) {
result[j++] = i;
count++;
}
}
System.out.println(count + "_____________");
for (int i = 0; i < count; i++) {
System.out.println(result[i]);
}
}
private static boolean isExist(int[] result, int i) {
for (int j : result) {
if (j == i) {
return true;
}
}
return false;
}
}
import java.util.ArrayList;
public class Subset { //Generate all subsets by generating all binary numbers
public static ArrayList<ArrayList<Integer>> getSubsets2(ArrayList<Integer> set) {
ArrayList<ArrayList<Integer>> allsubsets =
new ArrayList<ArrayList<Integer>>();
int max = 1 << set.size(); //there are 2 power n
for (int i = 0; i < max; i++) {
ArrayList<Integer> subset = new ArrayList<Integer>();
int index = 0;
while (i > 0) {
if ((i & 1) > 0) {
subset.add(set.get(index)); //Add elements to a new ArrayList
}
i >>= 1;
index++;
}
allsubsets.add(subset);
}
return allsubsets;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
ArrayList<Integer> set = new ArrayList<Integer>(); //Create an ArrayList
set.add(1);
set.add(2);
System.out.println(getSubsets2(set));
}
}
The result should be [[],[1],[2],[1,2]]
But I can't get the result, the exception is as follows:
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
Your while loop is incorrect.
Made slightly more succinct with a for-loop:
import java.util.ArrayList;
public class Subset { //Generate all subsets by generating all binary numbers
public static ArrayList<ArrayList<Integer>> getSubsets2(ArrayList<Integer> set) {
ArrayList<ArrayList<Integer>> allsubsets =
new ArrayList<ArrayList<Integer>>();
int max = 1 << set.size(); //there are 2 power n different subsets
for (int i = 0; i < max; i++) {
ArrayList<Integer> subset = new ArrayList<Integer>();
for (int j = 0; j < set.size(); j++) {
if (((i >> j) & 1) == 1) {
subset.add(set.get(j));
}
}
allsubsets.add(subset);
}
return allsubsets;
}
public static void main(String[] args) {
ArrayList<Integer> set = new ArrayList<Integer>(); //Create an ArrayList
set.add(1);
set.add(2);
System.out.println(getSubsets2(set));
}
}
Bear in mind that the subset operation is exponential, so you'll get a very large number of elements. The implementation above will only work with about 32 input elements, as that yields 2^32 output subsets, which will very easily run you over the limit of an array...
Your problem appears to be in your loop. If you look at it:
for (int i = 0; i < max; i++) {
ArrayList<Integer> subset = new ArrayList<Integer>();
int index = 0;
while (i > 0) {
if ((i & 1) > 0) {
subset.add(set.get(index)); //Add elements to a new ArrayList
}
i >>= 1;
index++;
}
allsubsets.add(subset);
}
You'll notice that the outside for-loop is trying to count i upwards from zero, and the inner while loop counts it back to zero every iteration, so the outer loop runs forever.
Here is a Java 8 solution for this question:
public Set<Set<Integer>> getSubsets(Set<Integer> set) {
if (set.isEmpty()) {
return Collections.singleton(Collections.emptySet());
}
Set<Set<Integer>> subSets = set.stream().map(item -> {
Set<Integer> clone = new HashSet<>(set);
clone.remove(item);
return clone;
}).map(group -> getSubsets(group))
.reduce(new HashSet<>(), (x, y) -> {
x.addAll(y);
return x;
});
subSets.add(set);
return subSets;
}
Program runs forever. Below statement execute continuesly and getting outOfMemory. Variable i value is never bigger than max value, check it.
`subset.add(set.get(index));`
In a nutshell, your inner while-loop is changing the outer for-loop's loop variable (i). This is disrupting the outer loop iteration. At the end of the inner loop the value of i is going to be zero ... which means that the outer loop will never terminate.
Given what you are doing, the fix is to use a different variable (say j) for the inner loop, and initialize it from i.
This illustrates why it is a bad idea to change a for-loop variable inside the loop.
how about a recursive solution?
vector<vector<int> > getSubsets(vector<int> a){
//base case
//if there is just one item then its subsets are that item and empty item
//for example all subsets of {1} are {1}, {}
if(a.size() == 1){
vector<vector<int> > temp;
temp.push_back(a);
vector<int> b;
temp.push_back(b);
return temp;
}
else
{
//here is what i am doing
// getSubsets({1, 2, 3})
//without = getSubsets({1, 2})
//without = {1}, {2}, {}, {1, 2}
//with = {1, 3}, {2, 3}, {3}, {1, 2, 3}
//total = {{1}, {2}, {}, {1, 2}, {1, 3}, {2, 3}, {3}, {1, 2, 3}}
//return total
int last = a[a.size() - 1];
a.pop_back();
vector<vector<int> > without = getSubsets(a);
vector<vector<int> > with = without;
for(int i=0;i<without.size();i++){
with[i].push_back(last);
}
vector<vector<int> > total;
for(int j=0;j<without.size();j++){
total.push_back(without[j]);
}
for(int k=0;k<with.size();k++){
total.push_back(with[k]);
}
return total;
}
}
In other words, can I do something like
for() {
for {
for {
}
}
}
Except N times? In other words, when the method creating the loops is called, it is given some parameter N, and the method would then create N of these loops nested one in another?
Of course, the idea is that there should be an "easy" or "the usual" way of doing it. I already have an idea for a very complicated one.
jjnguy is right; recursion lets you dynamically create variable-depth nesting. However, you don't get access to data from the outer layers without a little more work. The "in-line-nested" case:
for (int i = lo; i < hi; ++i) {
for (int j = lo; j < hi; ++j) {
for (int k = lo; k < hi; ++k) {
// do something **using i, j, and k**
}
}
}
keeps the variables i, j, and k in scope for the innermost body to use.
Here's one quick hack to do that:
public class NestedFor {
public static interface IAction {
public void act(int[] indices);
}
private final int lo;
private final int hi;
private final IAction action;
public NestedFor(int lo, int hi, IAction action) {
this.lo = lo;
this.hi = hi;
this.action = action;
}
public void nFor (int depth) {
n_for (0, new int[0], depth);
}
private void n_for (int level, int[] indices, int maxLevel) {
if (level == maxLevel) {
action.act(indices);
} else {
int newLevel = level + 1;
int[] newIndices = new int[newLevel];
System.arraycopy(indices, 0, newIndices, 0, level);
newIndices[level] = lo;
while (newIndices[level] < hi) {
n_for(newLevel, newIndices, maxLevel);
++newIndices[level];
}
}
}
}
The IAction interface stipulates the role of a controlled action which takes an array of indices as the argument to its act method.
In this example, each instance of NestedFor is configured by the constructor with the iteration limits and the action to be performed by the innermost level. The parameter of the nFor method specifies how deeply to nest.
Here's a sample usage:
public static void main(String[] args) {
for (int i = 0; i < 4; ++i) {
final int depth = i;
System.out.println("Depth " + depth);
IAction testAction = new IAction() {
public void act(int[] indices) {
System.out.print("Hello from level " + depth + ":");
for (int i : indices) { System.out.print(" " + i); }
System.out.println();
}
};
NestedFor nf = new NestedFor(0, 3, testAction);
nf.nFor(depth);
}
}
and the (partial) output from its execution:
Depth 0
Hello from level 0:
Depth 1
Hello from level 1: 0
Hello from level 1: 1
Hello from level 1: 2
Depth 2
Hello from level 2: 0 0
Hello from level 2: 0 1
Hello from level 2: 0 2
Hello from level 2: 1 0
Hello from level 2: 1 1
Hello from level 2: 1 2
Hello from level 2: 2 0
Hello from level 2: 2 1
Hello from level 2: 2 2
Depth 3
Hello from level 3: 0 0 0
Hello from level 3: 0 0 1
Hello from level 3: 0 0 2
Hello from level 3: 0 1 0
...
Hello from level 3: 2 1 2
Hello from level 3: 2 2 0
Hello from level 3: 2 2 1
Hello from level 3: 2 2 2
It sounds like you may want to look into recursion.
2015 Edit: Along the same vain as the previous incantation, I made the following package to handle this; https://github.com/BeUndead/NFor
The usage would be as follows
public static void main(String... args) {
NFor<Integer> nfor = NFor.of(Integer.class)
.from(0, 0, 0)
.by(1, 1, 1)
.to(2, 2, 3);
for (Integer[] indices : nfor) {
System.out.println(java.util.Arrays.toString(indices));
}
}
resulting in
[0, 0, 0]
[0, 0, 1]
[0, 0, 2]
[0, 1, 0]
[0, 1, 1]
[0, 1, 2]
[1, 0, 0]
[1, 0, 1]
[1, 0, 2]
[1, 1, 0]
[1, 1, 1]
[1, 1, 2]
It also supports conditions other than lessThan. The usage there being (with import static NFor.*;):
NFor<Integer> nfor = NFor.of(Integer.class)
.from(-1, 3, 2)
.by(1, -2, -1)
.to(lessThanOrEqualTo(1), greaterThanOrEqualTo(-1), notEqualTo(0));
Resulting in:
[-1, 3, 2]
[-1, 3, 1]
[-1, 1, 2]
[-1, 1, 1]
[-1, -1, 2]
[-1, -1, 1]
[0, 3, 2]
[0, 3, 1]
[0, 1, 2]
[0, 1, 1]
[0, -1, 2]
[0, -1, 1]
[1, 3, 2]
[1, 3, 1]
[1, 1, 2]
[1, 1, 1]
[1, -1, 2]
[1, -1, 1]
Obviously, loops of different lengths and different classes (all boxed, numeric primitives) are supported. The default (if not specified) is from(0, ...).by(1, ...); but a to(...) must be specified.
The NForTest file should demonstrate several different ways to use it.
The basic premise of this being to simply advance the 'indices' each turn rather than use recursion.
You might want to explain what you really want to do.
If the outer for loops are doing nothing but controlling a count, then your nested for loops are simply a more complicated way of iterating by a count that could be handled by a single for loop.
For example:
for (x = 0; x < 10; ++x) {
for (y = 0; y < 5; ++y) {
for (z = 0; z < 20; ++z) {
DoSomething();
}
}
}
Is equivalent to:
for (x = 0; x < 10*5*20; ++x) {
DoSomething();
}
I was actually thinking about this the other day.
An example that is probably not perfect but pretty close to what I think is being asked would be printing out a directory tree
public void printTree(directory) {
for(files in directory) {
print(file);
if(file is directory) {
printTree(file);
}
}
}
this way you end up with a stack of for loops nested inside each other, without the hassle of figuring out exactly how they should go together.
The essential idea behind nesting loops is multiplication.
Expanding on Michael Burr's answer, if the outer for loops are doing nothing but controlling a count, then your nested for loops over n counts are simply a more complicated way of iterating over the product of the counts with a single for loop.
Now, let's extend this idea to Lists. If you're iterating over three lists in nested loops, this is simply a more complicated way of iterating over the product of the lists with a single loop. But how do you express the product of three lists?
First, we need a way of expressing the product of types. The product of two types X and Y can be expressed as a generic type like P2<X, Y>. This is just a value that consists of two values, one of type X, the other of type Y. It looks like this:
public abstract class P2<A, B> {
public abstract A _p1();
public abstract B _p2();
}
For a product of three types, we just have P3<A, B, C>, with the obvious third method. A product of three lists, then, is achieved by distributing the List functor over the product type. So the product of List<X>, List<Y>, and List<Z> is simply List<P3<X, Y, Z>>. You can then iterate over this list with a single loop.
The Functional Java library has a List type that supports multiplying lists together using first-class functions and product types (P2, P3, etc. which are also included in the library).
For example:
for (String x : xs) {
for (String y : ys) {
for (String z : zs) {
doSomething(x, y, z);
}
}
}
Is equivalent to:
for (P3<String, String, String> p : xs.map(P.p3()).apply(ys).apply(zs)) {
doSomething(p._1(), p._2(), p._3());
}
Going further with Functional Java, you can make doSomething first-class, as follows. Let's say doSomething returns a String:
public static final F<P3<String, String, String>, String> doSomething =
new F<P3<String, String, String>, String>() {
public String f(final P3<String, String, String> p) {
return doSomething(p._1(), p._2(), p._3());
}
};
Then you can eliminate the for-loop altogether, and collect the results of all the applications of doSomething:
List<String> s = xs.map(P.p3()).apply(ys).apply(zs).map(doSomething);
Problem needs more specification. Maybe recursion will help you, but keep in mind that recursion is almost always an alternative to iteration, and vice versa. It may be that a 2-level nested loop can be sufficient for your needs. Just let us know what problem you're trying to solve.
The neatest general approach I could come up with in Java 7 is
// i[0] = 0..1 i[1]=0..3, i[2]=0..4
MultiForLoop.loop( new int[]{2,4,5}, new MultiForLoop.Callback() {
void act(int[] i) {
System.err.printf("%d %d %d\n", i[0], i[1], i[2] );
}
}
Or in Java 8:
// i[0] = 0..1 i[1]=0..3, i[2]=0..4
MultiForLoop.loop( new int[]{2,4,5},
i -> { System.err.printf("%d %d %d\n", i[0], i[1], i[2]; }
);
An implementation that supports this is:
/**
* Uses recursion to perform for-like loop.
*
* Usage is
*
* MultiForLoop.loop( new int[]{2,4,5}, new MultiForLoop.Callback() {
* void act(int[] indices) {
* System.err.printf("%d %d %d\n", indices[0], indices[1], indices[2] );
* }
* }
*
* It only does 0 - (n-1) in each direction, no step or start
* options, though they could be added relatively trivially.
*/
public class MultiForLoop {
public static interface Callback {
void act(int[] indices);
}
static void loop(int[] ns, Callback cb) {
int[] cur = new int[ns.length];
loop(ns, cb, 0, cur);
}
private static void loop(int[] ns, Callback cb, int depth, int[] cur) {
if(depth==ns.length) {
cb.act(cur);
return;
}
for(int j = 0; j<ns[depth] ; ++j ) {
cur[depth]=j;
loop(ns,cb, depth+1, cur);
}
}
}
If you are having a general nested-loop structure like:
for(i0=0;i0<10;i0++)
for(i1=0;i1<10;i1++)
for(i2=0;i2<10;i2++)
....
for(id=0;id<10;id++)
printf("%d%d%d...%d\n",i0,i1,i2,...id);
where i0,i1,i2,...,id are loop variables and d is the depth of the nested loop.
Equivalent Recursion Solution:
void nestedToRecursion(counters,level){
if(level == d)
computeOperation(counters,level);
else
{
for (counters[level]=0;counters[level]<10;counters[level]++)
nestedToRecursion(counters,level+1);
}
}
void computeOperation(counters,level){
for (i=0;i<level;i++)
printf("%d",counters[i]);
printf("\n");
}
counters is an array of size d, representing the corresponding variables i0,i1,i2,...id respectively int counters[d].
nestedToRecursion(counters,0);
Similarly we can convert other variables like initializing of recursion or ending by using arrays for them, i.e. we could have initial[d], ending[d].
A Java 8 solution based on streams:
public static Stream<int[]> nest(Supplier<IntStream> first, Supplier<IntStream>... streams) {
Stream<int[]> result = first.get().mapToObj(i -> new int[]{i});
for (Supplier<IntStream> s : streams) {
result = nest(result, s);
}
return result;
}
private static Stream<int[]> nest(Stream<int[]> source, Supplier<IntStream> target) {
return source.flatMap(b -> target.get().mapToObj(i -> {
int[] result = new int[b.length + 1];
System.arraycopy(b, 0, result, 0, b.length);
result[b.length] = i;
return result;
}));
}
Another one which is not thread-safe, but avoid extra copies:
public static Stream<int[]> nest(Supplier<IntStream>... streams) {
final int[] buffer = new int[streams.length];
Stream<int[]> result = Stream.of(buffer);
for (int n = 0; n < streams.length; n++) {
result = nest(result, streams[n], n);
}
// Might need to perform a copy here, if indices are stored instead of being consumed right away.
// return result.map(b -> Arrays.copyOf(b, b.length));
return result;
}
private static Stream<int[]> nest(Stream<int[]> source, Supplier<IntStream> target, int index) {
return source.flatMap(b -> target.get().mapToObj(i -> {
b[index] = i;
return b;
}));
}
Usage:
nest(
() -> IntStream.range(0, 2),
() -> IntStream.range(0, 2),
() -> IntStream.range(0, 3))
.forEach(indices -> System.out.println( Arrays.toString(indices)));
Output:
[0, 0, 0]
[0, 0, 1]
[0, 0, 2]
[0, 1, 0]
[0, 1, 1]
[0, 1, 2]
[1, 0, 0]
[1, 0, 1]
[1, 0, 2]
[1, 1, 0]
[1, 1, 1]
[1, 1, 2]
public void recursiveFor(Deque<Integer> indices, int[] ranges, int n) {
if (n != 0) {
for (int i = 0; i < ranges[n-1]; i++) {
indices.push(i);
recursiveFor(indices, ranges, n-1);
indices.pop();
}
}
else {
// inner most loop body, access to the index values thru indices
System.out.println(indices);
}
}
Sample call:
int[] ranges = {2, 2, 2};
recursiveFor(new ArrayDeque<Integer>(), ranges, ranges.length);
String fors(int n){
StringBuilder bldr = new StringBuilder();
for(int i = 0; i < n; i++){
for(int j = 0; j < i; j++){
bldr.append('\t');
}
bldr.append("for() {\n");
}
for(int i = n-1; i >= 0; i--){
for(int j = 0; j < i; j++){
bldr.append('\t');
}
bldr.append("}\n");
}
return bldr.toString();
}
Creates a nice nested for-loop skeleton ;-)
Not completely serious and i'm aware that a recursive solution would have been more elegant.
my first time answering a question but i felt like i needed to share this info
of
`
for (x = 0; x < base; ++x) {
for (y = 0; y < loop; ++y) {
DoSomething();
}
}
being equivalent to
for (x = 0; x < base*loop; ++x){
DoSomething();
}
so if you wanted an n number of nests, it can be written using division between base and loop so it could look something as simple as this:
char[] numbs = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
public void printer(int base, int loop){
for (int i = 0; i < pow(base, loop); i++){
int remain = i;
for (int j = loop-1; j >= 0; j--){
int digit = remain/int(pow(base, j));
print(numbs[digit]);
remain -= digit*pow(base, j);
}
println();
}
}
so if you were to type printer(10, 2); it would print out:
00
01
02
03
04
...
97
98
99
This worked for me really nice - I had to select from some alternatives, which were stored in myAlternativePaths and the basic idea is that I was trying to construct next selection, and when there was an "overflow" in one dimension / component, you just reinitialize that dimension and add one to the next.
public boolean isValidAlternativeSelection (int[] alternativesSelected) {
boolean allOK = true;
int nPaths= myAlternativePaths.size();
for (int i=0; i<nPaths; i++) {
allOK=allOK & (alternativesSelected[i]<myAlternativePaths.get(i).myAlternativeRoutes.size());
}
return allOK;
}
public boolean getNextValidAlternativeSelection (int[] alternativesSelected) {
boolean allOK = true;
int nPaths= myAlternativePaths.size();
alternativesSelected[0]=alternativesSelected[0]+1;
for (int i=0; i<nPaths; i++) {
if (alternativesSelected[i]>=myAlternativePaths.get(i).myAlternativeRoutes.size()) {
alternativesSelected[i]=0;
if(i<nPaths-1) {
alternativesSelected[i+1]=alternativesSelected[i+1]+1;
} else {
allOK = false;
}
}
// allOK=allOK & (alternativesSelected[i]<myAlternativePaths.get(i).myAlternativeRoutes.size());
}
return allOK;
}
I also tried to solve this problem and eventually have created this simple solution.
For example, suppose we need to generate loops like this dynamically:
for (int i = 0; i < 2; i++) {
for (int j = 1; j < 3; j++) {
for (int k = 2; k < 4; k++) {
System.out.println(Arrays.asList(i, j, k));
}
}
}
So, we can implement it with a such builder:
new Loops()
.from(0).to(2)
.from(1).to(3)
.from(2).to(4)
.action(System.out::println);
The result of execution:
[0, 1, 2]
[0, 1, 3]
[0, 2, 2]
[0, 2, 3]
[1, 1, 2]
[1, 1, 3]
[1, 2, 2]
[1, 2, 3]
I hope it will useful for someone else too.
In case if you want to work on data and not just numbers. Following solution could be tried:
class WordGenerator {
//My custom spell checker.
//It returns an empty string if the word is not there in dictionary
public static MySpellChecker spellCheck;
public static void main(String args[]) throws Exception {
spellCheck = new MySpellChecker();
List<String> consonants = List.of("c","t");
List<String> vowels = List.of("a","o","");
//adding to this list will increase nesting
List<List<String>> input = new ArrayList<>();
input.add(consonants);
input.add(vowels);
input.add(vowels);
input.add(consonants);
MyForLoop fLoop = new MyForLoop(input.listIterator(), //for nesting loops
new ArrayList<String>(), //loop state
//action to perform in innermost loop
(state)->spellCheck.check(String.join("", state)));
//start execution
fLoop.accept("");
//print results
System.out.println("No of iterations: " + fLoop.getResult().size());
System.out.println("\nFound words: " + String.join(", ", fLoop.getResult()));
}
}
class MyForLoop implements Consumer<String> {
private static List<String> result = new ArrayList<>();
private ListIterator<List<String>> itr;
private Function<List<String>, String> action;
private List<String> state = new ArrayList<>();
public MyForLoop(ListIterator<List<String>> itr, List<String> collected, Function<List<String>, String> action) {
this.itr = itr;
this.action = action;
state = new ArrayList<>(collected);
}
#Override
public void accept(String s) {
if(!s.isBlank())
state.add(s);
if(itr.hasNext()) {
itr.next().stream().forEach(new MyForLoop(itr, state, action));
if(!state.isEmpty())
state.remove(state.size()-1);
itr.previous();
} else {
result.add(action.apply(state));
state.remove(state.size()-1);
}
}
public static List<String> getResult() {
return result;
}
}
Output:
No of iterations: 36
Found words: , , , , , cat, , coat, , coot, , cot, , , , , , , , , , , , tat, , toat, , toot, toc, tot, , , , , ,
Here the code is generating words starting and ending with 'c' and 't', with at max two vowels in between them. You change sequence in input list to change word creation.
The MyForLoop object maintains a state list, that holds current iteration state. Each element of the state list gives state of corresponding level of the nested for loop. The state can be used in action, that gets executed in inner most loop.
To keep the demo code short and simple I've cut corners.😋 It can be improved in many ways.
I've used Jazzy library to check spellings.
<dependency>
<groupId>net.sf.jazzy</groupId>
<artifactId>jazzy</artifactId>
<version>0.5.2-rtext-1.4.1-2</version>
</dependency>
In the interest of conciseness I am putting my code here :
void variDepth(int depth, int n, int i) {
cout<<"\n d = "<<depth<<" i = "<<i;
if(!--depth) return;
for(int i = 0;i<n;++i){
variDepth(depth,n,i);
}
}
void testVariDeapth()
{ variDeapth(3, 2,0);
}
Output
d = 3 i = 0
d = 2 i = 0
d = 1 i = 0
d = 1 i = 1
d = 2 i = 1
d = 1 i = 0
d = 1 i = 1