Related
I have the two arrays:
String[] operators = {"+", "-", "*"};
int[] numbers = {48, 24, 12, 6};
And I want to get all possible combination in a String format like this:
48+24+12+6
48+24+12-6
48+24+12*6
48+24-12+6
48+24-12-6
48+24-12*6
..........
48*24*12*6
This what I have tried:
for (int i = 0; i < operators.length; i++) {
System.out.println(numbers[0] + operators[i] + numbers[1] +
operators[i] + numbers[2] + operators[i] + numbers[3]);
}
But it only prints:
48+24+12+6
48-24-12-6
48*24*12*6
How to solve this?
This is not a duplicate because I don't want to get every two pairs of data, I want to get every combination in 4 pairs. The duplicate is different.
Use a triple loop:
for (int i=0; i < operators.length; ++i) {
for (int j=0; j < operators.length; ++j) {
for (int k=0; k < operators.length; ++k) {
System.out.println(numbers[0] + operators[i] + numbers[1] + operators[j] +
numbers[2] + operators[k] + numbers[3]);
}
}
}
You essentially want to take the cross product of the operators vector (if it were a vector). In Java, this translates to a triply-nested set of loops.
While #TimBiegeleisen solution would work like a charm, its complexity might be an issue. The better approach would be a code like this:
static void combinationUtil(
int[] arr, int n, int r, int index, int[] data, int i) {
// Current combination is ready to be printed, print it
if (index == r) {
for (int j = 0; j < r; j++)
System.out.print(data[j] + " ");
System.out.println("");
return;
}
// When no more elements are there to put in data[]
if (i >= n)
return;
// current is included, put next at next location
data[index] = arr[i];
combinationUtil(arr, n, r, index + 1, data, i + 1);
// current is excluded, replace it with next (Note that
// i+1 is passed, but index is not changed)
combinationUtil(arr, n, r, index, data, i + 1);
}
// The main function that prints all combinations of size r
// in arr[] of size n. This function mainly uses combinationUtil()
static void printCombination(int arr[], int n, int r) {
// A temporary array to store all combination one by one
int data[] = new int[r];
// Print all combination using temprary array 'data[]'
combinationUtil(arr, n, r, 0, data, 0);
}
Source: GeeksForGeeks and my IDE :)
This sounds like a textbook case for a recursive solution:
public static void combineAndPrint(String[] pieces, String[] operators) {
if (pieces.length < 1) {
// no pieces? do nothing!
} else if (pieces.length == 1) {
// just one piece? no need to join anything, just print it!
System.out.println(pieces[0]);
} else {
// make a new array that's one piece shorter
String[] newPieces = new String[pieces.length - 1];
// copy all but the first two pieces into it
for (int i = 2; i < pieces.length; i++) {
newPieces[i - 1] = pieces[i];
}
// combine the first two pieces and recurse
for (int i = 0; i < operators.length; i++) {
newPieces[0] = pieces[0] + operators[i] + pieces[1];
combineAndPrint(newPieces, operators);
}
}
}
public static void main(String[] args) {
String[] operators = {"+", "-", "*"};
String[] numbers = {"48", "24", "12", "6"};
combineAndPrint(numbers, operators);
}
Try it online!
BTW, to generalize this method so that you can do more things with the generated expressions than just printing them, I would recommend making it accept an extra Consumer<String> parameter. That is, you could rewrite the method declaration as:
public static void combine(String[] pieces, String[] operators, Consumer<String> consumer) {
and replace the System.out.println(pieces[0]) with consumer.accept(pieces[0]) and the recursive call to combineAndPrint(newPieces, operators) with combine(newPieces, operators, consumer). Then just call it from your main method e.g. as:
combine(numbers, operators, s -> System.out.println(s));
Try it online!
(Of course, doing it in this more flexible way requires a somewhat modern Java version — Java 8 or later, to be specific — whereas the first example I showed above should work on even ancient versions all the way down to Java 1.0. Maybe in some future version of Java we'll get proper support for coroutines and generators, like Python and Kotlin and even modern JS already have, and then we won't even need to pass the consumer around any more.)
As already pointed out by findusl in his answer, the problem here is, strictly speaking, not to find any sort of "combination of two arrays". Instead, you basically just want to find all possible combinations of the available operators.
(The fact that you later want to "interveave" them with operands is rather unrelated to the core of the question)
So here is another option for solving this: You can create an iterable over all combinations of a certain number of elements from a certain set (in your case: the operators) and then simply combine the results with the other set (in your case: the operands).
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
public class OperatorsTest {
public static void main(String[] args) {
String[] operators = {"+", "-", "*"};
int[] numbers = {48, 24, 12, 6};
CombinationIterable<String> iterable =
new CombinationIterable<String>(3, Arrays.asList(operators));
for (List<String> element : iterable) {
System.out.println(interveave(element, numbers));
}
}
private static String interveave(List<String> operators, int numbers[]) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < operators.size(); i++) {
sb.append(numbers[i]);
sb.append(operators.get(i));
}
sb.append(numbers[numbers.length - 1]);
return sb.toString();
}
}
class CombinationIterable<T> implements Iterable<List<T>> {
private final List<T> input;
private final int sampleSize;
private final int numElements;
public CombinationIterable(int sampleSize, List<T> input) {
this.sampleSize = sampleSize;
this.input = input;
numElements = (int) Math.pow(input.size(), sampleSize);
}
#Override
public Iterator<List<T>> iterator() {
return new Iterator<List<T>>() {
private int current = 0;
private final int chosen[] = new int[sampleSize];
#Override
public boolean hasNext() {
return current < numElements;
}
#Override
public List<T> next() {
if (!hasNext()) {
throw new NoSuchElementException("No more elements");
}
List<T> result = new ArrayList<T>(sampleSize);
for (int i = 0; i < sampleSize; i++) {
result.add(input.get(chosen[i]));
}
increase();
current++;
return result;
}
private void increase() {
int index = chosen.length - 1;
while (index >= 0) {
if (chosen[index] < input.size() - 1) {
chosen[index]++;
return;
}
chosen[index] = 0;
index--;
}
}
};
}
}
The task resembles that of finding a set of operations that can be done with a certain number of operands and operators, and thus, this Q/A may be related. But whether or not things like associativity or commutativity should be considered here was not mentioned in the question.
I made an alternative, overengineered (but flexible!) "business" solution. The array lengths and values (numbers and operators) can be flexible.
package test1;
import java.io.IOException;
import java.util.ArrayList;
public class MainClass {
public static void main(String[] args) throws IOException {
String[] operators = {"+", "-", "*"};
int[] numbers = {48, 24, 12, 6};
ArrayList<String> strings =
new MainClass().getAllPossibleCombinations(numbers, operators);
for (String string : strings) {
System.out.println(string);
}
}
private ArrayList<String> getAllPossibleCombinations(
int[] numbers, String[] operators) {
if (numbers.length < 2)
throw new IllegalArgumentException(
"Length of numbers-array must be at least 2");
if (operators.length < 1)
throw new IllegalArgumentException(
"Length of operators-array must be at least 1");
ArrayList<String> returnList = new ArrayList<>();
int[] indexes = new int[numbers.length - 1];
while (true) {
StringBuilder line = new StringBuilder();
for (int i = 0; i < numbers.length; i++) {
int number = numbers[i];
line.append(number);
if (i < indexes.length) {
line.append(operators[indexes[i]]);
}
}
returnList.add(line.toString());
try {
this.updateIndexes(indexes, operators.length - 1);
} catch (NoMoreCombinationsException e) {
break;
}
}
return returnList;
}
private void updateIndexes(int[] currentIndexes, int maxValue)
throws NoMoreCombinationsException {
if (this.intArrayIsOnly(currentIndexes, maxValue)) {
throw new NoMoreCombinationsException();
}
for (int i = currentIndexes.length - 1; i >= 0; i--) {
int currentIndex = currentIndexes[i];
if (currentIndex < maxValue) {
currentIndexes[i] = currentIndex + 1;
break;
} else {
currentIndexes[i] = 0;
}
}
}
private boolean intArrayIsOnly(int[] array, int value) {
for (int iteratedValue : array) {
if (iteratedValue != value) return false;
}
return true;
}
}
class NoMoreCombinationsException extends Exception {
public NoMoreCombinationsException() {
}
public NoMoreCombinationsException(String message) {
super(message);
}
public NoMoreCombinationsException(String message, Throwable cause) {
super(message, cause);
}
public NoMoreCombinationsException(Throwable cause) {
super(cause);
}
public NoMoreCombinationsException(
String message, Throwable cause,
boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
Works like a charm :)
A bit of background information why the answers are they way they are. This problem is not really called "all possible combinations" as that is usually the problem where you can represent the elements as bits and switch them to 0 or 1 whether the element is included or not. This has a complexity of 2^N where N is the amount of operators you have. This can be solved easily in a single loop.
However in your case you have the "urn problem with replacement and sequence". The complexity of this is N^n where n is the amount of spots you have to fill with operators. (This is often seen for pincodes where each spots can be 10 values). So because this is of higher complexity than the "all possible combinations" problem you need multiple loops or recursive calls.
So to answer the question, "how to solve this?". You have to solve it with multiple loops or recursion because of the underlying problem's complexity.
I've developed a class that covers this use case and many others. I call it the TallyCounter. Your question would be answered with this class like this:
package app;
import java.util.HashMap;
import java.util.Map;
import app.TallyCounter.Type;
public class App {
public static void main(String args[]) throws Exception {
Map<Long, String> map = new HashMap<>();
map.put(0l, "+");
map.put(1l, "-");
map.put(2l, "*");
TallyCounter counter = new TallyCounter(3, Type.NORMAL, 2);
do {
System.out.format("48%s24%s12%s6\n",
map.get(counter.getArray()[2]),
map.get(counter.getArray()[1]),
map.get(counter.getArray()[0])
);
counter.increment();
} while (!counter.overflowFlag);
}
}
You don't need multiple loops or recursion.
Here's an example showcasing a limited number of loops and no recursion at all.
int[][] combine(int[] values) {
int size = values.length;
int combinations = 1;
for (int i = 0; i < size; i++) {
combinations *= size;
}
// or int combinations = (int)Math.pow(size, size);
int[][] result = new int[combinations][size];
for (int i = 0; i < combinations; i++) {
int index = i;
for (int j = 0; j < size; j++) {
result[i][j] = values[index % size];
index /= size;
}
}
return result;
}
If you use it with three elements, [1, 2, 3], as in the code below:
void testCombine() {
int[][] combinations = combine(new int[]{1, 2, 3});
for (int[] combination : combinations) {
System.out.println(Arrays.toString(combination));
}
}
You end up with the following result:
[1, 1, 1]
[2, 1, 1]
[3, 1, 1]
[1, 2, 1]
[2, 2, 1]
[3, 2, 1]
[1, 3, 1]
[2, 3, 1]
[3, 3, 1]
[1, 1, 2]
[2, 1, 2]
[3, 1, 2]
[1, 2, 2]
[2, 2, 2]
[3, 2, 2]
[1, 3, 2]
[2, 3, 2]
[3, 3, 2]
[1, 1, 3]
[2, 1, 3]
[3, 1, 3]
[1, 2, 3]
[2, 2, 3]
[3, 2, 3]
[1, 3, 3]
[2, 3, 3]
[3, 3, 3]
You can use streams to get all possible combinations of two arrays. First, iterate over the numbers array and append the operator signs to each number, you get an array like this: {"48+", "48-", "48*"} for each number. The number of operators may vary. Then reduce this stream of arrays to a single array by sequentially multiplying array pairs, you get an array of possible combinations.
Try it online!
String[] operators = {"+", "-", "*"};
int[] numbers = {48, 24, 12, 6};
// an array of possible combinations
String[] comb = IntStream.range(0, numbers.length)
// append each substring with possible
// combinations, except the last one
// return Stream<String[]>
.mapToObj(i -> numbers.length - 1 > i ?
Arrays.stream(operators)
.map(op -> numbers[i] + op)
.toArray(String[]::new) :
new String[]{"" + numbers[i]})
// reduce stream of arrays to a single array
// by sequentially multiplying array pairs
.reduce((arr1, arr2) -> Arrays.stream(arr1)
.flatMap(str1 -> Arrays.stream(arr2)
.map(str2 -> str1 + str2))
.toArray(String[]::new))
.orElse(null);
// column-wise output (three columns in this case)
int columns = (int) Math.pow(operators.length, numbers.length - 2);
IntStream.range(0, columns)
.mapToObj(i -> IntStream.range(0, comb.length)
.filter(j -> j % columns == i)
.mapToObj(j -> comb[j])
.collect(Collectors.joining(" | ")))
.forEach(System.out::println);
Output:
48+24+12+6 | 48-24+12+6 | 48*24+12+6
48+24+12-6 | 48-24+12-6 | 48*24+12-6
48+24+12*6 | 48-24+12*6 | 48*24+12*6
48+24-12+6 | 48-24-12+6 | 48*24-12+6
48+24-12-6 | 48-24-12-6 | 48*24-12-6
48+24-12*6 | 48-24-12*6 | 48*24-12*6
48+24*12+6 | 48-24*12+6 | 48*24*12+6
48+24*12-6 | 48-24*12-6 | 48*24*12-6
48+24*12*6 | 48-24*12*6 | 48*24*12*6
See also: Generate all possible string combinations by replacing the hidden “#” number sign
I have this array :
int[][] multi = new int[][]{
{ 3, 4, 2},
{ 2, 2, 5 },
{ 1, 2 }
};
I would like to print the produce of each cells. It's pretty hard to explain so lets see some example :
For my table i need to print :
6 //(3*2*1)
12 //(3*2*2)
6 //(3*2*1)
12 //(3*2*2)
15 //(3*5*1)
30 //(3*5*2)
8 //(4*2*1)
16 //(4*2*2)
8 //(4*2*1)
16 //(4*2*2)
20 //(4*5*1)
40 //(4*5*2)
...
Size of table can change, i need a generic things.
Here is my start but it's not doing what i need. This is looping line by line...
for (int i = 0; i<multi[0].length; i++) {
for (int k = 0; k < multi.length; k++) {
for (int l = 0; l < multi[k].length; l++ ) {
System.err.println(multi[k][l]);
}
}
}
I thing you have to do that recursively if your dimensions of array is not fixed..
I came up the code for dynamic dimension of 2D array
public class HelloWorld{
static int[][] multi = new int[][]{
{ 3, 4, 2},
{ 2, 2, 5 },
{ 1, 2 }
};
static public void pattern(int row,int multip) {
if(row >= multi.length) {
System.out.println(multip);
return ;
}
for(int i = 0; i<multi[row].length;i++) {
multip*=multi[row][i];
row+=1;
pattern(row,multip);
row-=1;
multip/=multi[row][i];
}
}
public static void main(String []args){
pattern(0,1);
}
}
If your dimensions are fixed then you can also do that using above logic but for that if you want to do iterative then you have to repeatedly create loops inside loop.
It's not hard to explain if you use mathematics terms and what you need is simply a Cartesian product of the sets (i.e. each row) in your bidimensional array.
It could be a bit longer to explain here the theory about Cartesian product (X is the operator) but in practice you have to calculate the result of:
((multi[0] X multi[1]) X ...) X multi[n]
And you ends with a bidimensional array with a number of rows which is the product of all the cardinality of each set and each row has a number of elements which is the number of the sets (because each tupla has an element from each set).
Another thing is that the tuple are ordered i.e. the element of a set will be in the same position in all the tuples e.g. each tupla in position 0 will have an element of multi[0].
Knowing these properties is possible to create the product with a construction algorithm which puts the elements of the first set in the first column of the resulting set repeating them the necessary amount of time and then go on with the next set/next column.
At the end when you have your Cartesian product you can do anything you want e.g. calculate the product of the elements of each row.
public class CartesianProductProduct {
public int[][] product(int[][] sets) {
int cardinality = 1;
for (int is = 0; is < sets.length; is++) cardinality *= sets[is].length;
int[][] cartesianProduct = new int[cardinality][sets.length];
int curCardinality = 1;
for (int is = 0; is < sets.length; is++) {
curCardinality *= sets[is].length;
int repetition = cardinality / curCardinality;
int ie = 0;
for (int ic = 0; ic < cardinality; ic++) {
cartesianProduct[ic][is] = sets[is][ie];
if (repetition == 1) {
ie++;
} else if ((ic + 1) % repetition == 0) {
ie++;
}
ie = ie == sets[is].length ? 0 : ie;
}
}
return cartesianProduct;
}
public static void main(String[] args) {
int[][] multi = new int[][]{
{3, 4, 2},
{2, 2, 5},
{1, 2}
};
int[][] cartesianProduct = new CartesianProductProduct().product(multi);
for (int i = 0; i < cartesianProduct.length; i++) {
int prod = 1;
String s = "";
String sep = "";
for (int k = 0; k < cartesianProduct[i].length; k++) {
prod *= cartesianProduct[i][k];
s = s + sep + cartesianProduct[i][k];
sep = "*";
}
System.out.printf("%s //(%s)\n", prod, s);
}
}
}
I just had an online coding interview and one of the questions asked there is for a given array of integers, find out the number of pairs whose summation is equal to a certain number (passed as parameter inside the method ). For example an array is given as,
int[] a = {3, 2, 1, 45, 27, 6, 78, 9, 0};
int k = 9; // given number
So, there will be 2 pairs (3, 6) and (9, 0) whose sum is equal to 9. It's good to mention that how the pairs are formed doesn't matter. The means (3,6) and (6,3) will be considered as same pair. I provided the following solution (in Java) and curious to know if I missed any edge cases?
public static int numberOfPairs(int[] a, int k ){
int len = a.length;
if (len == 0){
return -1;
}
Arrays.sort(a);
int count = 0, left = 0, right = len -1;
while( left < right ){
if ( a[left] + a[right] == k ){
count++;
if (a[left] == a[left+1] && left < len-1 ){
left++;
}
if ( a[right] == a[right-1] && right >1 ){
right-- ;
}
right--; // right-- or left++, otherwise, will get struck in the while loop
}
else if ( a[left] + a[right] < k ){
left++;
}
else {
right--;
}
}
return count;
}
Besides, can anyone propose any alternative solution of the problem ? Thanks.
Following solution will return the number of unique pairs
public static int numberOfPairs(Integer[] array, int sum) {
Set<Integer> set = new HashSet<>(Arrays.asList(array));
// this set will keep track of the unique pairs.
Set<String> uniquePairs = new HashSet<String>();
for (int i : array) {
int x = sum - i;
if (set.contains(x)) {
int[] y = new int[] { x, i };
Arrays.sort(y);
uniquePairs.add(Arrays.toString(y));
}
}
//System.out.println(uniquePairs.size());
return uniquePairs.size();
}
The time complexity will be O(n).
Hope this helps.
You can use the HashMap<K,V> where K: a[i] and V: k-a[i]
This may result in an incorrect answer if there are duplicates in an array.
Say for instances:
int a[] = {4, 4, 4, 4, 4, 4, 4, 4, 4}
where k = 8 or:
int a[] = {1, 3, 3, 3, 3, 1, 2, 1, 2}
where k = 4.
So in order to avoid that, we can have a List<List<Integer>> , which can check each pair and see if it is already in the list.
static int numberOfPairs(int[] a, int k)
{
List<List<Integer>> res = new ArrayList<>();
Map<Integer, Integer> map = new HashMap<>();
for(int element:a)
{
List<Integer> list = new ArrayList<>();
if(map.containsKey(element))
{
list.add(element);
list.add(map.get(element));
if(!res.contains(list))
res.add(list);
}
else
map.put(k - element, element);
}
return res.size();
}
Your solution is overly complex, you can do this exercise in a much easier manner:
public static int numberOfPairs(int[] a, int k ){
int count=0;
List<Integer> dedup = new ArrayList<>(new HashSet<>(Arrays.asList(a)));
for (int x=0 ; x < dedup.size() ; x++ ){
for (int y=x+1 ; y < dedup.size() ; y++ ){
if (dedup.get(x)+dedup.get(y) == k)
count++;
}
}
return count;
}
The trick here is to have a loop starting after the first loop's index to not count the same values twice, and not compare it with your own index. Also, you can deduplicate the array to avoid duplicate pairs, since they don't matter.
You can also sort the list, then break the loop as soon as your sum goes above k, but that's optimization.
This code will give you count of the pairs that equals to given sum and as well as the pair of elements that equals to sum
private void pairofArrayElementsEqualstoGivenSum(int sum,Integer[] arr){
int count=0;
List numList = Arrays.asList(arr);
for (int i = 0; i < arr.length; i++) {
int num = sum - arr[i];
if (numList.contains(num)) {
count++;
System.out.println("" + arr[i] + " " + num + " = "+sum);
}
}
System.out.println("Total count of pairs "+count);
}
Given an array of integers and a target value, determine the number of pairs of array elements with a difference equal to a target value.
The function has the following parameters:
k: an integer, the target difference
arr: an array of integers
Using LINQ this is nice solution:
public static int CountNumberOfPairsWithDiff(int k, int[] arr)
{
var numbers = arr.Select((value) => new { value });
var pairs = from num1 in numbers
join num2 in numbers
on num1.value - k equals num2.value
select new[]
{
num1.value, // first number in the pair
num2.value, // second number in the pair
};
foreach (var pair in pairs)
{
Console.WriteLine("Pair found: " + pair[0] + ", " + pair[1]);
}
return pairs.Count();
}
I need to create a multidemensional ArrayList to hold String values. I know how to do this with a standard array, like so: public static String[][] array = {{}} but this is no good because I don't know the size of my array, all I know is how many dimensions it will have.
How can I make a 'dynamically resizable array with 2/+ demensions'?
Edit/Update
Maybe it would be easier to resize or define a standard array using a varible? But I don't know?
It's probably easier to use my original idea of an ArrayList though... All I need is a complete example code to create a 2D ArrayList and add so example values to both dimensions without knowing the index.
ArrayList<ArrayList<String>> array = new ArrayList<ArrayList<String>>();
Depending on your requirements, you might use a Generic class like the one below to make access easier:
import java.util.ArrayList;
class TwoDimentionalArrayList<T> extends ArrayList<ArrayList<T>> {
public void addToInnerArray(int index, T element) {
while (index >= this.size()) {
this.add(new ArrayList<T>());
}
this.get(index).add(element);
}
public void addToInnerArray(int index, int index2, T element) {
while (index >= this.size()) {
this.add(new ArrayList<T>());
}
ArrayList<T> inner = this.get(index);
while (index2 >= inner.size()) {
inner.add(null);
}
inner.set(index2, element);
}
}
If you're allowed to use predefined Java classes, you could do something like:
private static ArrayList<ArrayList<String>> biDemArrList = new ArrayList<ArrayList<String>>();
Then you can add new elements, something like:
ArrayList<String> temp = new ArrayList<String>(); // added ()
temp.add("Hello world.");
biDemArrList.add(temp);
Hope you can understand what I mean and what's going on. Also, you'll need to import java.util.ArrayList; for this, if you're making use of the Java class.
ArrayList<ArrayList<String>>
http://download.oracle.com/javase/6/docs/api/java/util/ArrayList.html
http://en.wikipedia.org/wiki/Generics_in_Java
Once I required 2-D arrayList and I created using List and ArrayList and the code is as follows:
import java.util.*;
public class ArrayListMatrix {
public static void main(String args[]){
List<ArrayList<Integer>> a = new ArrayList<>();
ArrayList<Integer> a1 = new ArrayList<Integer>();
ArrayList<Integer> a2 = new ArrayList<Integer>();
ArrayList<Integer> a3 = new ArrayList<Integer>();
a1.add(1);
a1.add(2);
a1.add(3);
a2.add(4);
a2.add(5);
a2.add(6);
a3.add(7);
a3.add(8);
a3.add(9);
a.add(a1);
a.add(a2);
a.add(a3);
for(ArrayList obj:a){
ArrayList<Integer> temp = obj;
for(Integer job : temp){
System.out.print(job+" ");
}
System.out.println();
}
}
}
Output:
1 2 3
4 5 6
7 8 9
Source : https://www.codepuran.com/java/2d-matrix-arraylist-collection-class-java/
I can think of An Array inside an Array or a Guava's MultiMap?
e.g.
ArrayList<ArrayList<String>> matrix = new ArrayList<ArrayList<String>>();
You can have ArrayList with elements which would be ArrayLists itself.
Wouldn't List<ArrayList<String>> 2dlist = new ArrayList<ArrayList<String>>(); be a better (more efficient) implementation?
Here an answer for those who'd like to have preinitialized lists of lists. Needs Java 8+.
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
class Scratch {
public static void main(String[] args) {
int M = 4;
int N = 3;
// preinitialized array (== list of lists) of strings, sizes not fixed
List<List<String>> listOfListsOfString = initializeListOfListsOfT(M, N, "-");
System.out.println(listOfListsOfString);
// preinitialized array (== list of lists) of int (primitive type), sizes not fixed
List<List<Integer>> listOfListsOfInt = initializeListOfListsOfInt(M, N, 7);
System.out.println(listOfListsOfInt);
}
public static <T> List<List<T>> initializeListOfListsOfT(int m, int n, T initValue) {
return IntStream
.range(0, m)
.boxed()
.map(i -> new ArrayList<T>(IntStream
.range(0, n)
.boxed()
.map(j -> initValue)
.collect(Collectors.toList()))
)
.collect(Collectors.toList());
}
public static List<List<Integer>> initializeListOfListsOfInt(int m, int n, int initValue) {
return IntStream
.range(0, m)
.boxed()
.map(i -> new ArrayList<>(IntStream
.range(0, n)
.map(j -> initValue)
.boxed()
.collect(Collectors.toList()))
)
.collect(Collectors.toList());
}
}
Output:
[[-, -, -], [-, -, -], [-, -, -], [-, -, -]]
[[7, 7, 7], [7, 7, 7], [7, 7, 7], [7, 7, 7]]
Side note for those wondering about IntStream:
IntStream
.range(0, m)
.boxed()
is equivalent to
Stream
.iterate(0, j -> j + 1)
.limit(n)
Credit goes for JAcob Tomao for the code.
I only added some comments to help beginners like me understand it.
I hope it helps.
// read about Generic Types In Java & the use of class<T,...> syntax
// This class will Allow me to create 2D Arrays that do not have fixed sizes
class TwoDimArrayList<T> extends ArrayList<ArrayList<T>> {
public void addToInnerArray(int index, T element) {
while (index >= this.size()) {
// Create enough Arrays to get to position = index
this.add(new ArrayList<T>()); // (as if going along Vertical axis)
}
// this.get(index) returns the Arraylist instance at the "index" position
this.get(index).add(element); // (as if going along Horizontal axis)
}
public void addToInnerArray(int index, int index2, T element) {
while (index >= this.size()) {
this.add(new ArrayList<T>());// (as if going along Vertical
}
//access the inner ArrayList at the "index" position.
ArrayList<T> inner = this.get(index);
while (index2 >= inner.size()) {
//add enough positions containing "null" to get to the position index 2 ..
//.. within the inner array. (if the requested position is too far)
inner.add(null); // (as if going along Horizontal axis)
}
//Overwrite "null" or "old_element" with the new "element" at the "index 2" ..
//.. position of the chosen(index) inner ArrayList
inner.set(index2, element); // (as if going along Horizontal axis)
}
}
What would you think of this for 3D ArrayList - can be used similarly to
arrays - see the comments in the code:
import java.util.ArrayList;
import java.util.List;
/**
* ArrayList3D simulates a 3 dimensional array,<br>
* e.g: myValue = arrayList3D.get(x, y, z) is the same as: <br>
* myValue = array[x][y][z] <br>
* and<br>
* arrayList3D.set(x, y, z, myValue) is the same as:<br>
* array[x][y][z] = myValue; <br>
* but keeps its full ArrayList functionality, thus its
* benefits of ArrayLists over arrays.<br>
* <br>
* #param <T> data type
*/
public class ArrayList3D <T> {
private final List<List<List<T>>> arrayList3D;
public ArrayList3D() {
arrayList3D = newArrayDim1();
}
/**
* Get value of the given array element.<br>
* E.g: get(2, 5, 3);<br>
* For 3 dim array this would equal to:<br>
* nyValue = array[2][5][3];<br>
* <br>
* Throws: IndexOutOfBoundsException
* - if any index is out of range
* (index < 0 || index >= size())<br>
* <br>
* #param dim1 index of the first dimension of the array list
* #param dim2 index of the second dimension of the array list
* #param dim3 index of the third dimension of the array list
* #return value of the given array element (of type T)
*/
public T get(int dim1, int dim2, int dim3) {
List<List<T>> ar2 = arrayList3D.get(dim1);
List<T> ar3 = ar2.get(dim2);
return ar3.get(dim3);
}
/**
* Set value of the given array.<br>
* E.g: set(2, 5, 3, "my value");<br>
* For 3 dim array this would equal to:<br>
* array[2][5][3]="my value";<br>
* <br>
* Throws: IndexOutOfBoundsException
* - if any index is out of range
* (index < 0 || index >= size())<br>
* <br>
* #param dim1 index of the first dimension of the array list
* #param dim2 index of the second dimension of the array list
* #param dim3 index of the third dimension of the array list
* #param value value to assign to the given array
* <br>
*/
public void set(int dim1, int dim2, int dim3, T value) {
arrayList3D.get(dim1).get(dim2).set(dim3, value);
}
/**
* Set value of the given array element.<br>
* E.g: set(2, 5, 3, "my value");<br>
* For 3 dim array this would equal to:<br>
* array[2][5][3]="my value";<br>
* <br>
* Throws: IndexOutOfBoundsException
* - if any index is less then 0
* (index < 0)<br>
* <br>
* #param indexDim1 index of the first dimension of the array list
* #param indexDim2 index of the second dimension of the array list
* If you set indexDim1 or indexDim2 to value higher
* then the current max index,
* the method will add entries for the
* difference. The added lists will be empty.
* #param indexDim3 index of the third dimension of the array list
* If you set indexDim3 to value higher
* then the current max index,
* the method will add entries for the
* difference and fill in the values
* of param. 'value'.
* #param value value to assign to the given array index
*/
public void setOrAddValue(int indexDim1,
int indexDim2,
int indexDim3,
T value) {
List<T> ar3 = setOrAddDim3(indexDim1, indexDim2);
int max = ar3.size();
if (indexDim3 < 0)
indexDim3 = 0;
if (indexDim3 < max)
ar3.set(indexDim3, value);
for (int ix = max-1; ix < indexDim3; ix++ ) {
ar3.add(value);
}
}
private List<List<List<T>>> newArrayDim1() {
List<T> ar3 = new ArrayList<>();
List<List<T>> ar2 = new ArrayList<>();
List<List<List<T>>> ar1 = new ArrayList<>();
ar2.add(ar3);
ar1.add(ar2);
return ar1;
}
private List<List<T>> newArrayDim2() {
List<T> ar3 = new ArrayList<>();
List<List<T>> ar2 = new ArrayList<>();
ar2.add(ar3);
return ar2;
}
private List<T> newArrayDim3() {
List<T> ar3 = new ArrayList<>();
return ar3;
}
private List<List<T>> setOrAddDim2(int indexDim1) {
List<List<T>> ar2 = null;
int max = arrayList3D.size();
if (indexDim1 < 0)
indexDim1 = 0;
if (indexDim1 < max)
return arrayList3D.get(indexDim1);
for (int ix = max-1; ix < indexDim1; ix++ ) {
ar2 = newArrayDim2();
arrayList3D.add(ar2);
}
return ar2;
}
private List<T> setOrAddDim3(int indexDim1, int indexDim2) {
List<List<T>> ar2 = setOrAddDim2(indexDim1);
List<T> ar3 = null;
int max = ar2.size();
if (indexDim2 < 0)
indexDim2 = 0;
if (indexDim2 < max)
return ar2.get(indexDim2);
for (int ix = max-1; ix < indexDim2; ix++ ) {
ar3 = newArrayDim3();
ar2.add(ar3);
}
return ar3;
}
public List<List<List<T>>> getArrayList3D() {
return arrayList3D;
}
}
And here is a test code:
ArrayList3D<Integer> ar = new ArrayList3D<>();
int max = 3;
for (int i1 = 0; i1 < max; i1++) {
for (int i2 = 0; i2 < max; i2++) {
for (int i3 = 0; i3 < max; i3++) {
ar.setOrAddValue(i1, i2, i3, (i3 + 1) + (i2*max) + (i1*max*max));
int x = ar.get(i1, i2, i3);
System.out.println(" - " + i1 + ", " + i2 + ", " + i3 + " = " + x);
}
}
}
Result output:
0, 0, 0 = 1
0, 0, 1 = 2
0, 0, 2 = 3
0, 1, 0 = 4
0, 1, 1 = 5
0, 1, 2 = 6
0, 2, 0 = 7
0, 2, 1 = 8
0, 2, 2 = 9
1, 0, 0 = 10
1, 0, 1 = 11
1, 0, 2 = 12
1, 1, 0 = 13
1, 1, 1 = 14
1, 1, 2 = 15
1, 2, 0 = 16
1, 2, 1 = 17
1, 2, 2 = 18
2, 0, 0 = 19
2, 0, 1 = 20
2, 0, 2 = 21
2, 1, 0 = 22
2, 1, 1 = 23
2, 1, 2 = 24
2, 2, 0 = 25
2, 2, 1 = 26
2, 2, 2 = 27
You can also do something like this ...
First create and Initialize the matrix or multidimensional arraylist
ArrayList<ArrayList<Integer>> list;
MultidimentionalArrayList(int x,int y)
{
list = new ArrayList<>();
for(int i=0;i<=x;i++)
{
ArrayList<Integer> temp = new ArrayList<>(Collections.nCopies(y+1,0));
list.add(temp);
}
}
Add element at specific position
void add(int row,int column,int val)
{
list.get(row).set(column,val); // list[row][column]=val
}
This static matrix can be change into dynamic if check that row and
column are out of bound. just insert extra temp arraylist for row
remove element
int remove(int row, int column)
{
return list.get(row).remove(column);// del list[row][column]
}
ArrayList<ArrayList<Integer>> C = new ArrayList<ArrayList<Integer>>();
ArrayList<Integer> a = new ArrayList<Integer>();
a.addAll(Arrays.asList(7, 3));
ArrayList<Integer> b = new ArrayList<Integer>();
b.addAll(Arrays.asList(2, 1));
ArrayList<Integer> c = new ArrayList<Integer>();
c.addAll(Arrays.asList(4, 9));
C.addAll(Arrays.asList(a, b, c));
C.forEach(System.out::print);
You can simply use:
ArrayList<ArrayList<T>> multiDimentionalArray = new ArrayList<ArrayList<T>>();
You can change T to whatever data type you need
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