PopulationIterator.java

package net.bmahe.genetics4j.core;

import java.util.Iterator;

import org.apache.commons.lang3.Validate;

/**
 * Iterator implementation for traversing individuals in a population during evolutionary algorithms.
 * 
 * <p>PopulationIterator provides a standard Java Iterator interface for accessing individuals
 * in a {@link Population}, combining genotypes with their corresponding fitness values to create
 * complete {@link Individual} instances during iteration.
 * 
 * <p>This iterator enables convenient traversal patterns such as:
 * <ul>
 * <li><strong>Enhanced for loops</strong>: Iterate over individuals using for-each syntax</li>
 * <li><strong>Stream operations</strong>: Convert populations to streams for functional processing</li>
 * <li><strong>Sequential access</strong>: Process individuals one at a time without loading all into memory</li>
 * <li><strong>Collection integration</strong>: Use with Java Collection framework methods</li>
 * </ul>
 * 
 * <p>The iterator maintains internal state to track the current position and constructs
 * {@link Individual} objects on-demand by combining genotypes and fitness values from the
 * underlying population at the same index.
 * 
 * <p>Key characteristics:
 * <ul>
 * <li><strong>Type safety</strong>: Parameterized with fitness type for compile-time type checking</li>
 * <li><strong>Lazy evaluation</strong>: Creates Individual objects only when requested</li>
 * <li><strong>Memory efficient</strong>: Doesn't duplicate population data, references original</li>
 * <li><strong>Standard interface</strong>: Implements Java Iterator contract completely</li>
 * </ul>
 * 
 * <p>Usage patterns:
 * <pre>{@code
 * // Enhanced for loop iteration
 * Population<Double> population = getPopulation();
 * for (Individual<Double> individual : population) {
 *     System.out.println("Fitness: " + individual.fitness());
 * }
 * 
 * // Stream-based processing
 * population.stream()
 *     .filter(individual -> individual.fitness() > threshold)
 *     .mapToDouble(Individual::fitness)
 *     .average();
 * 
 * // Manual iteration
 * Iterator<Individual<Double>> iterator = population.iterator();
 * while (iterator.hasNext()) {
 *     Individual<Double> individual = iterator.next();
 *     processIndividual(individual);
 * }
 * }</pre>
 * 
 * <p>Thread safety considerations:
 * <ul>
 * <li><strong>Single-threaded use</strong>: Iterator instances are not thread-safe</li>
 * <li><strong>Population stability</strong>: Underlying population should not be modified during iteration</li>
 * <li><strong>Concurrent iterations</strong>: Multiple iterators can be created for the same population</li>
 * </ul>
 * 
 * @param <T> the type of fitness values in the population, must be comparable for selection operations
 * @see Population
 * @see Individual
 * @see java.util.Iterator
 */
public class PopulationIterator<T extends Comparable<T>> implements Iterator<Individual<T>> {

	private final Population<T> population;

	private int currentIndex = 0;

	/**
	 * Constructs a new iterator for the specified population.
	 * 
	 * <p>Creates an iterator that will traverse all individuals in the given population,
	 * starting from index 0 and proceeding sequentially through all individuals.
	 * 
	 * @param _population the population to iterate over
	 * @throws IllegalArgumentException if the population is null
	 */
	public PopulationIterator(final Population<T> _population) {
		Validate.notNull(_population);

		this.population = _population;
	}

	/**
	 * Returns {@code true} if there are more individuals to iterate over.
	 * 
	 * <p>Checks whether the current position is within the bounds of the population.
	 * This method can be called multiple times without advancing the iterator position.
	 * 
	 * @return {@code true} if there are more individuals, {@code false} if all have been visited
	 */
	@Override
	public boolean hasNext() {
		return currentIndex < population.size();
	}

	/**
	 * Returns the next individual in the population and advances the iterator position.
	 * 
	 * <p>Constructs an {@link Individual} by combining the genotype and fitness value
	 * at the current position, then advances to the next position for subsequent calls.
	 * 
	 * @return the next individual in the iteration sequence
	 * @throws java.util.NoSuchElementException if there are no more individuals (when {@link #hasNext()} returns false)
	 */
	@Override
	public Individual<T> next() {
		final Genotype genotype = population.getGenotype(currentIndex);
		final T fitness = population.getFitness(currentIndex);
		currentIndex++;
		return Individual.of(genotype, fitness);
	}
}