Thursday, October 2, 2014

Iteration/Enumerator

Using Iterators to Overcome Array-based Problems

Using simple array-based iteration not only ties algorithms to using arrays, but also requires that the
logic for determining which elements stay, which go, and in which order to process them, is known in
advance.

An iterator (also known as an enumerator) solves these problems by providing a generic interface for
looping over a set of data so that the underlying data structure or storage mechanism—such as an array,
database, and so on—is hidden

Whereas simple iteration generally requires you to write specific code
to handle where the data is sourced from or even what kind of ordering or preprocessing is required, an
iterator enables you to write simpler, more generic algorithms

Iterator Operations

public interface Iterator {
public void first();

public void last();

public boolean isDone();

public void next();

public void previous();

public Object current() throws IteratorOutOfBoundsException;
}

Not all data structures allow traversing the data in both directions, nor does it always make sense.

For this reason, it is acceptable for any of the traversal methods—first(), last(), next(), and previous()—to throw an UnsupportedOperationException to indicate this missing or unimplemented behavior

public class IteratorOutOfBoundsException extends RuntimeException {
}

The Iterable Interface

Iterable is an interface that provides a generic way to obtain an iterator from any data structure that supports it.

public interface Iterable {
public Iterator iterator();
}

Using an Iterator

Once an iterator has been obtained—
either by explicit construction or as an argument to a method—position to the beginning or end as
appropriate

Iterator iterator = ...;
iterator.first();
while (!iterator.isDone()) {
Object object = iterator.current();
...
iterator.next();
}

Iterator iterator = ...;
for (iterator.first();!iterator.isDone(); iterator.next()) {
Object object = iterator.current();
...
}

Standard Iterators

Array Iterator

The most obvious iterator implementation is one that wraps an array. 
By encapsulating an array within an iterator, you can start writing applications that operate on arrays now and still extend easily to other data structures in the future.


Reverse Iterator

With a reverse iterator, however, the same behavior can be achieved without re-sorting and without duplicated code.

When the application calls first(), the reverse iterator actually calls last() on the underlying iterator. When the application calls next(), the underlying iterator’s previous() method is invoked, and so on. In this way, the behavior of the iterator can be reversed without changing the client
code that displays the results, and without re-sorting the array

Filtering Iterator

One of the more interesting and useful advantages of using iterators is the capability to wrap or decorate
(see the Decorator pattern [Gamma, 1995]) another iterator to filter the return values

The filter iterator works by wrapping another iterator and only returning values that satisfy some condition,
known as a predicate

Each time the underlying iterator is called, the returned value is passed to the
predicate to determine whether it should be kept or discarded

public interface Predicate {
public boolean evaluate(Object object);
}

evaluate(), that is called for each value, and returning a Boolean to indicate whether the value meets the selection criteria or not


No comments:

Post a Comment