MultiIntCounter.java

package net.bmahe.genetics4j.core.util;

import java.util.Arrays;

import org.apache.commons.lang3.Validate;

public class MultiIntCounter {

	final int[] indices;
	final int[] maxIndices;

	public MultiIntCounter(final int... maxIndices) {
		Validate.notNull(maxIndices);
		Validate.isTrue(maxIndices.length > 0);

		for (int i = 0; i < maxIndices.length; i++) {
			final int maxIndex = maxIndices[i];
			Validate.isTrue(maxIndex > 0);
		}

		this.indices = new int[maxIndices.length];
		this.maxIndices = Arrays.copyOf(maxIndices, maxIndices.length);
	}

	public int[] getIndices() {
		return indices;
	}

	public int getIndex(final int index) {
		Validate.isTrue(index >= 0);
		Validate.isTrue(index < indices.length);

		return indices[index];
	}

	public int[] getMaxIndices() {
		return maxIndices;
	}

	public int getTotal() {
		int total = 1;
		for (int i : maxIndices) {
			total *= i;
		}
		return total;
	}

	public boolean hasNext() {

		/**
		 * Precondition check if we tried all the combinations
		 */
		boolean allToTheMax = false;
		for (int i = 0; i < indices.length && !allToTheMax; i++) {
			if (indices[i] >= maxIndices[i]) {
				allToTheMax = true;
			}
		}
		return allToTheMax == false;
	}

	/**
	 * 
	 * @param indices
	 * @param maxIndices
	 * @return true if indices was successfully updates; false if there are no new
	 *         cases
	 */
	public int[] next() {

		Validate.isTrue(hasNext());

		boolean carryOver = true;
		int currentIndex = 0;
		while (carryOver && currentIndex < indices.length) {

			indices[currentIndex] += 1;

			if (indices[currentIndex] >= maxIndices[currentIndex] && currentIndex < indices.length - 1) {
				indices[currentIndex] = 0;

				for (int j = 0; j < currentIndex; j++) {
					indices[j] = 0;
				}

				currentIndex++;
				carryOver = true;
			} else {
				carryOver = false;
			}

		}

		return indices;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + Arrays.hashCode(indices);
		result = prime * result + Arrays.hashCode(maxIndices);
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		MultiIntCounter other = (MultiIntCounter) obj;
		if (!Arrays.equals(indices, other.indices))
			return false;
		if (!Arrays.equals(maxIndices, other.maxIndices))
			return false;
		return true;
	}

	@Override
	public String toString() {
		return "MultiIntCounter [indices=" + Arrays.toString(indices) + ", maxIndices=" + Arrays.toString(maxIndices)
				+ "]";
	}
}