(See the previous iteration here.)
This time, I have incorporated the answer from YawarRaza7349.
Now, my code looks like this:
io.github.coderodde.util.IndexTupleIterable.java:
package io.github.coderodde.util;
import java.util.Iterator;
/**
* This class provides an iterable for iterating over list index tuples.
*
* @version 1.0.0
* @since 1.0.0
*/
public final class IndexTupleIterable implements Iterable<int[]> {
/**
* The length of the index tuples.
*/
private final int indexTupleLength;
/**
* The length of the list for which the indices are being generated.
*/
private final int lengthOfTargetList;
public IndexTupleIterable(final int indexTupleLength,
final int lengthOfTargetList) {
this.indexTupleLength = indexTupleLength;
this.lengthOfTargetList = lengthOfTargetList;
}
@Override
public Iterator<int[]> iterator() {
return new IndexTupleIterator(indexTupleLength,
lengthOfTargetList);
}
}
io.github.coderodde.util.IndexTupleIterator.java:
package io.github.coderodde.util;
import java.util.Arrays;
import java.util.Iterator;
import java.util.NoSuchElementException;
/**
* This class implements an iterator that generates index tuples in
* lexicographic order.
*
* @version 1.0.0
* @since 1.0.0
*/
public final class IndexTupleIterator implements Iterator<int[]>{
/**
* The length of the index tuples.
*/
private final int indexTupleLength;
/**
* The length of the list for which the indices are being generated.
*/
private final int lengthOfTargetList;
/**
* The actual internal state containing the current index tuple.
*/
private final int[] indices;
/**
* The last value for the first index. As soon the first index reaches this
* value, we can halt generating further index tuples since we have
* generated all of them.
*/
private int lastValueForFirstIndex;
public IndexTupleIterator(final int indexTupleLength,
final int lengthOfTargetList) {
checkArguments(indexTupleLength,
lengthOfTargetList);
this.indexTupleLength = indexTupleLength;
this.lengthOfTargetList = lengthOfTargetList;
this.indices = new int[indexTupleLength];
this.lastValueForFirstIndex = lengthOfTargetList - indexTupleLength;
initState();
}
@Override
public boolean hasNext() {
return indices[0] < lastValueForFirstIndex;
}
@Override
public int[] next() {
if (!hasNext()) {
throw new NoSuchElementException("Nothing left to iterate.");
}
if (indices[indexTupleLength - 1] < lengthOfTargetList - 1) {
indices[indexTupleLength - 1]++;
return indices;
}
for (int i = indexTupleLength - 2; i >= 0; --i) {
final int a = indices[i];
final int b = indices[i + 1];
if (a < b - 1) {
indices[i]++;
for (int j = i + 1; j < indexTupleLength; j++) {
indices[j] = indices[j - 1] + 1;;
}
return indices;
}
}
throw new IllegalStateException("Should not get here.");
}
@Override
public void remove() {
throw new UnsupportedOperationException(
"remove() is not supported in IndexTupleIterator.");
}
public static void main(String[] args) {
int lineNumber = 1;
for (final int[] indexTuple : new IndexTupleIterable(3, 6)) {
System.out.printf("%2d: %s\n",
lineNumber++,
Arrays.toString(indexTuple));
}
}
private void initState() {
// Create the initial index tuple <0, 1, ..., indexTupleLength - 1>:
for (int i = 0; i < indexTupleLength; ++i) {
indices[i] = i;
}
lastValueForFirstIndex = lengthOfTargetList - indexTupleLength;
// We need this in order to generate the first index tuple:
--indices[indexTupleLength - 1];
}
/**
* Checks that the input arguments are sensible.
*
* @param indexTupleLength the length of the index tuple.
* @param lengthOfTargetList the length of the list being indexed.
*/
private static void checkArguments(final int indexTupleLength,
final int lengthOfTargetList) {
if (indexTupleLength < 1) {
final String exceptionMessage =
String.format("indexTupleLength(%d) < 1",
indexTupleLength);
throw new IllegalArgumentException(exceptionMessage);
}
if (lengthOfTargetList < 1) {
final String exceptionMessage =
String.format("lengthOfTargetList(%d) < 1",
lengthOfTargetList);
throw new IllegalArgumentException(exceptionMessage);
}
if (indexTupleLength > lengthOfTargetList) {
final String exceptionMessage =
String.format(
"indexTupleLength(%d) > lengthOfTargetList(%d)",
indexTupleLength,
lengthOfTargetList);
throw new IllegalArgumentException(exceptionMessage);
}
}
}
As always, I am eager to hear any constructive commentary on my work.
IndexTupleIterator.next(). \$\endgroup\$