I have an array of integers: n[]
.
Also, I have an array (Nr[]
) contains n.length
integers. I need to generate all combinations of n[]
in a following way:
/* let n.length == 3 and Nr[0] = 2, Nr[1] = 3, Nr[2] = 3 */
n = {0, 0, 0};
n = {1, 0, 0};
n = {2, 0, 0};
n = {0, 1, 0};
n = {0, 2, 0};
n = {0, 3, 0};
n = {0, 0, 1};
...
n = {1, 1, 0};
n = {1, 2, 0};
n = {1, 3, 0};
n = {2, 1, 0};
n = {2, 2, 0};
n = {2, 3, 0};
n = {1, 1, 1};
...
n = {0, 1, 1};
// many others
The goal is to find all combinations of n
, where n[i]
can be 0 to Nr[i]
.
I did not succeed... How to solve it in Java? Or not in Java...
You might want to use recursion, try all possibilities for each index, and recursively invoke with the subarray, "without" the last element.
public static void printPermutations(int[] n, int[] Nr, int idx) {
if (idx == n.length) { //stop condition for the recursion [base clause]
System.out.println(Arrays.toString(n));
return;
}
for (int i = 0; i <= Nr[idx]; i++) {
n[idx] = i;
printPermutations(n, Nr, idx+1); //recursive invokation, for next elements
}
}
invoke with:
public static void main(String[] args) {
/* let n.length == 3 and Nr[0] = 2, Nr[1] = 3, Nr[2] = 3 */
int[] n = new int[3];
int Nr[] = {2,3,3 };
printPermutations(n, Nr, 0);
}
will get you:
[0, 0, 0]
[0, 0, 1]
[0, 0, 2]
[0, 0, 3]
[0, 1, 0]
[0, 1, 1]
[0, 1, 2]
[0, 1, 3]
[0, 2, 0]
[0, 2, 1]
[0, 2, 2]
[0, 2, 3]
[0, 3, 0]
[0, 3, 1]
[0, 3, 2]
[0, 3, 3]
[1, 0, 0]
[1, 0, 1]
[1, 0, 2]
[1, 0, 3]
[1, 1, 0]
[1, 1, 1]
[1, 1, 2]
[1, 1, 3]
[1, 2, 0]
[1, 2, 1]
[1, 2, 2]
[1, 2, 3]
[1, 3, 0]
[1, 3, 1]
[1, 3, 2]
[1, 3, 3]
[2, 0, 0]
[2, 0, 1]
[2, 0, 2]
[2, 0, 3]
[2, 1, 0]
[2, 1, 1]
[2, 1, 2]
[2, 1, 3]
[2, 2, 0]
[2, 2, 1]
[2, 2, 2]
[2, 2, 3]
[2, 3, 0]
[2, 3, 1]
[2, 3, 2]
[2, 3, 3]
Note however - that using this method does print all elements as you describes, but in a different order then your example.
Note: Unlike the question logic, the following code is upper-exclusive, as is the standard in Java, e.g. input of 3
will count from 0 to 2 (inclusive), not 0 to 3.
This can be done without recursion like this:
public static void printPermutations(int... size) {
int total = 1;
for (int i : size)
total *= i;
int[] n = new int[size.length];
for (int value = 0; value < total; value++) {
int remain = value;
for (int i = size.length - 1; i >= 0; i--) {
n[i] = remain % size[i];
remain /= size[i];
}
System.out.println(Arrays.toString(n));
}
}
Test
printPermutations(2, 3, 3);
Output
[0, 0, 0]
[0, 0, 1]
[0, 0, 2]
[0, 1, 0]
[0, 1, 1]
[0, 1, 2]
[0, 2, 0]
[0, 2, 1]
[0, 2, 2]
[1, 0, 0]
[1, 0, 1]
[1, 0, 2]
[1, 1, 0]
[1, 1, 1]
[1, 1, 2]
[1, 2, 0]
[1, 2, 1]
[1, 2, 2]
As an exercise in Java 8 streams, here is a class for iterating or streaming the permutations.
How to use:
// Using Iterator
for (int[] n : Permutations.iterable(2, 3, 3))
System.out.println(Arrays.toString(n));
// Using streams
Permutations.stream(2, 3, 3)
.parallel()
.map(Arrays::toString) // this will be done in parallel
.forEachOrdered(System.out::println);
// Getting all
int[][] results = Permutations.get(2, 3, 3);
for (int[] n : results)
System.out.println(Arrays.toString(n));
All three produce the same output as above.
Here is the code:
class Permutations implements Spliterator<int[]>, Iterator<int[]> {
public static Stream<int[]> stream(int... sizes) {
return StreamSupport.stream(spliterator(sizes), false);
}
public static Spliterator<int[]> spliterator(int... sizes) {
long total = sum(sizes);
return (total == 0 ? Spliterators.emptySpliterator() : new Permutations(sizes.clone(), 0, total));
}
public static Iterable<int[]> iterable(int... sizes) {
long total = sum(sizes);
if (total == 0)
return Collections.emptyList();
int[] clonedSizes = sizes.clone();
return new Iterable<int[]>() {
@Override public Iterator<int[]> iterator() { return new Permutations(clonedSizes, 0, total); }
@Override public Spliterator<int[]> spliterator() { return new Permutations(clonedSizes, 0, total); }
};
}
public static int[][] get(int... sizes) {
long total = sum(sizes);
if (total == 0)
return new int[0][];
if (total > Integer.MAX_VALUE)
throw new IllegalArgumentException("Invalid sizes (overflow): " + Arrays.toString(sizes));
Permutations generator = new Permutations(sizes.clone(), 0, total);
int[][] result = new int[(int) total][];
for (int i = 0; i < result.length; i++)
result[i] = generator.next();
return result;
}
private static long sum(int[] sizes) {
long total = 1;
for (int size : sizes) {
if (size < 0)
throw new IllegalArgumentException("Invalid size: " + size);
try {
total = Math.multiplyExact(total, size); // Java 8+: Fail on overflow
} catch (@SuppressWarnings("unused") ArithmeticException e) {
throw new IllegalArgumentException("Invalid sizes (overflow): " + Arrays.toString(sizes));
}
}
return total;
}
private final int[] sizes;
private final long end;
private long next;
Permutations(int[] sizes, long start, long end) {
this.sizes = sizes;
this.end = end;
this.next = start;
}
@Override
public boolean hasNext() {
return (this.next < this.end);
}
@Override
public int[] next() {
if (this.next == this.end)
throw new NoSuchElementException();
long value = this.next++;
int[] arr = new int[this.sizes.length];
for (int i = arr.length - 1; i >= 0; i--) {
arr[i] = (int) (value % this.sizes[i]);
value /= this.sizes[i];
}
return arr;
}
@Override
public int characteristics() {
// Note: Can easily be made SORTED by implementing a Comparator<int[]>
return ORDERED | DISTINCT | NONNULL | IMMUTABLE | SIZED | SUBSIZED; // not SORTED or CONCURRENT
}
@Override
public long estimateSize() {
return this.end - this.next;
}
@Override
public boolean tryAdvance(Consumer<? super int[]> action) {
if (this.next == this.end)
return false;
action.accept(next());
return true;
}
@Override
public Spliterator<int[]> trySplit() {
if (this.next > this.end - 2)
return null;
long split = (this.end - this.next) / 2 + this.next;
Permutations prefix = new Permutations(this.sizes, this.next, split);
this.next = split;
return prefix;
}
@Override
public void forEachRemaining(Consumer<? super int[]> action) {
Spliterator.super.forEachRemaining(action);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With