1
\$\begingroup\$

(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.

\$\endgroup\$
2
  • 1
    \$\begingroup\$ The use can completely break this by altering the contents of the integer array it receives from IndexTupleIterator.next(). \$\endgroup\$ Commented Jun 16 at 4:13
  • \$\begingroup\$ @TorbenPutkonen I know. \$\endgroup\$ Commented Jun 16 at 4:53

0

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.