VOOZH about

URL: https://en.wikibooks.org/wiki/Computer_Science_Design_Patterns/Iterator

⇱ Iterator - Wikibooks, open books for an open world


Jump to content
From Wikibooks, open books for an open world
👁 Image
Interpreter
Computer Science Design Patterns
Iterator
Mediator 👁 Image

Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation.

Examples

In Java, the interface java.util.Iterator<E> is an implementation of the iterator pattern. That way, all the objects that implement the java.lang.Iterable<T> interface don't need a handy implementation of this pattern.

Cost

This pattern has a cost. Only implement this pattern for an important amount of code. IDE refactoring can't help you much.

Creation

This pattern has a cost to create.

Maintenance

This pattern is easy to maintain.

Removal

This pattern has a cost to remove too.

Advises

  • Put the iterator term in the name of the iterator class to indicate the use of the pattern to the other developers.

Implementations

Implementation in Java

Java has the Iterator interface.

A simple example showing how to return integers between [start, end] using an Iterator

importjava.util.Iterator;
importjava.util.NoSuchElementException;

publicclass RangeIteratorExample{
publicstaticIterator<Integer>range(intstart,intend){
returnnewIterator<>(){
privateintindex=start;

@Override
publicbooleanhasNext(){
returnindex<end;
}

@Override
publicIntegernext(){
if(!hasNext()){
thrownewNoSuchElementException();
}
returnindex++;
}
};
}

publicstaticvoidmain(String[]args){
variterator=range(0,10);
while(iterator.hasNext()){
System.out.println(iterator.next());
}

// or using a lambda
iterator.forEachRemaining(System.out::println);
}
}

As of Java 5, objects implementing the Template:Javadoc:SE interface, which returns an Iterator from its only method, can be traversed using Java's foreach loop syntax. The Template:Javadoc:SE interface from the Java collections framework extends Iterable.

Example of class Family implementing the Iterable interface:
importjava.util.Iterator;
importjava.util.Set;

class Family<E>implementsIterable<E>{
privatefinalSet<E>elements;

publicFamily(Set<E>elements){
this.elements=Set.copyOf(elements);
}

@Override
publicIterator<E>iterator(){
returnelements.iterator();
}
}
The class IterableExample demonstrates the use of class Family :
publicclass IterableExample{
publicstaticvoidmain(String[]args){
varweasleys=Set.of(
"Arthur","Molly","Bill","Charlie",
"Percy","Fred","George","Ron","Ginny"
);
varfamily=newFamily<>(weasleys);

for(varname:family){
System.out.println(name+" Weasley");
}
}
}
Output:
Ron Weasley
Molly Weasley
Percy Weasley
Fred Weasley
Charlie Weasley
George Weasley
Arthur Weasley
Ginny Weasley
Bill Weasley

Here is another example in Java:

importjava.util.BitSet;
importjava.util.Iterator;
publicclass BitSetIteratorimplementsIterator<Boolean>{
privatefinalBitSetbitset;
privateintindex=0;
publicBitSetIterator(BitSetbitset){
this.bitset=bitset;
}
publicbooleanhasNext(){
returnindex<bitset.length();
}
publicBooleannext(){
if(index>=bitset.length()){
thrownewNoSuchElementException();
}
returnbitset.get(index++);
}
publicvoidremove(){
thrownewUnsupportedOperationException();
}
}

Two different usage examples:

importjava.util.BitSet;
publicclass TestClientBitSet{
publicstaticvoidmain(String[]args){
// create BitSet and set some bits
BitSetbitset=newBitSet();
bitset.set(1);
bitset.set(3400);
bitset.set(20);
bitset.set(47);
for(BitSetIteratoriter=newBitSetIterator(bitset);iter.hasNext();){
Booleanb=iter.next();
Stringtf=(b.booleanValue()?"T":"F");
System.out.print(tf);
}
System.out.println();
}
}
importjava.util.ArrayList;
importjava.util.Collection;
publicclass TestClientIterator{
publicstaticvoidmain(String[]args){
Collection<Object>al=newArrayList<Object>();
al.add(newInteger(42));
al.add("test");
al.add(newDouble("-12.34"));
for(Iterator<Object>iter=al.iterator();iter.hasNext();){
System.out.println(iter.next());
}
for(Objecto:al){
System.out.println(o);
}
}
}
Implementation in JavaScript

JavaScript, as part of ECMAScript 6, supports the iterator pattern with any object that provides a next() method, which returns an object with two specific properties: done and value. Here's an example that shows a reverse array iterator:

functionreverseArrayIterator(array){
varindex=array.length-1;
return{
next:()=>
index>=0?
{value:array[index--],done:false}:
{done:true}
}
}

constit=reverseArrayIterator(['three','two','one']);
console.log(it.next().value);//-> 'one'
console.log(it.next().value);//-> 'two'
console.log(it.next().value);//-> 'three'
console.log(`Are you done? ${it.next().done}`);//-> true

Most of the time, though, it is desirable to provide Iterator[1] semantics on objects so that they can be iterated automatically via for...of loops. Some of JavaScript's built-in types such as Array, Map, or Set already define their own iteration behavior. The same effect can be achieved by defining an object's meta @@iterator method, also referred to by Symbol.iterator. This creates an Iterable object.

Here's an example of a range function that generates a list of values starting from start to end, exclusive, using a regular for loop to generate the numbers:

functionrange(start,end){
return{
[Symbol.iterator](){// #A
returnthis;
},
next(){
if(start<end){
return{value:start++,done:false};// #B
}
return{done:true,value:end};// #B
}
}
}

for(numberofrange(1,5)){
console.log(number);// -> 1, 2, 3, 4
}

The iteration mechanism of built-in types, like strings, can also be manipulated:

letiter=['I','t','e','r','a','t','o','r'][Symbol.iterator]();
iter.next().value;//-> I
iter.next().value;//-> t
Implementation in C#

.NET Framework has special interfaces that support a simple iteration: System.Collections.IEnumerator over a non-generic collection and System.Collections.Generic.IEnumerator<T> over a generic collection.

C# statement foreach is designed to easily iterate through the collection that implements System.Collections.IEnumerator and/or System.Collections.Generic.IEnumerator<T> interface. Since C# v2, foreach is also able to iterate through types that implement System.Collections.Generic.IEnumerable<T> and System.Collections.Generic.IEnumerator<T> [2]

Example of using foreach statement:

varprimes=newList<int>{2,3,5,7,11,13,17,19};
longm=1;
foreach(varprimeinprimes)
m*=prime;

Here is another example in C#:

usingSystem;
usingSystem.Collections;
classMainApp
{
staticvoidMain()
{
ConcreteAggregatea=newConcreteAggregate();
a[0]="Item A";
a[1]="Item B";
a[2]="Item C";
a[3]="Item D";
// Create Iterator and provide aggregate
ConcreteIteratori=newConcreteIterator(a);
Console.WriteLine("Iterating over collection:");

objectitem=i.First();
while(item!=null)
{
Console.WriteLine(item);
item=i.Next();
}
// Wait for user
Console.Read();
}
}
// "Aggregate"
abstractclassAggregate
{
publicabstractIteratorCreateIterator();
}
// "ConcreteAggregate"
classConcreteAggregate:Aggregate
{
privateArrayListitems=newArrayList();
publicoverrideIteratorCreateIterator()
{
returnnewConcreteIterator(this);
}
// Property
publicintCount
{
get{returnitems.Count;}
}
// Indexer
publicobjectthis[intindex]
{
get{returnitems[index];}
set{items.Insert(index,value);}
}
}
// "Iterator"
abstractclassIterator
{
publicabstractobjectFirst();
publicabstractobjectNext();
publicabstractboolIsDone();
publicabstractobjectCurrentItem();
}
// "ConcreteIterator"
classConcreteIterator:Iterator
{
privateConcreteAggregateaggregate;
privateintcurrent=0;
// Constructor
publicConcreteIterator(ConcreteAggregateaggregate)
{
this.aggregate=aggregate;
}
publicoverrideobjectFirst()
{
returnaggregate[0];
}
publicoverrideobjectNext()
{
objectret=null;
if(current<aggregate.Count-1)
{
ret=aggregate[++current];
}

returnret;
}
publicoverrideobjectCurrentItem()
{
returnaggregate[current];
}
publicoverrideboolIsDone()
{
returncurrent>=aggregate.Count?true:false;
}
}
Implementation in PHP 5

PHP supports the iterator pattern via the Iterator interface, as part of the standard distribution.[3] Objects that implement the interface can be iterated over with the foreach language construct.

Example of patterns using PHP:

<?php

// BookIterator.php

namespace DesignPatterns;

class BookIterator implements \Iterator
{
 private int $i_position = 0;
 private BookCollection $booksCollection;

 public function __construct(BookCollection $booksCollection)
 {
 $this->booksCollection = $booksCollection;
 }

 public function current()
 {
 return $this->booksCollection->getTitle($this->i_position);
 }

 public function key(): int
 {
 return $this->i_position;
 }

 public function next(): void
 {
 $this->i_position++;
 }

 public function rewind(): void
 {
 $this->i_position = 0;
 }

 public function valid(): bool
 {
 return !is_null($this->booksCollection->getTitle($this->i_position));
 }
}
<?php

// BookCollection.php

namespace DesignPatterns;

class BookCollection implements \IteratorAggregate
{
 private array $a_titles = array();

 public function getIterator()
 {
 return new BookIterator($this);
 }

 public function addTitle(string $string): void
 {
 $this->a_titles[] = $string;
 }

 public function getTitle($key)
 {
 if (isset($this->a_titles[$key])) {
 return $this->a_titles[$key];
 }
 return null;
 }

 public function is_empty(): bool
 {
 return empty($this->$a_titles);
 }
}
<?php

// index.php

require 'vendor/autoload.php';
use DesignPatterns\BookCollection;

$booksCollection = new BookCollection();
$booksCollection->addTitle('Design Patterns');
$booksCollection->addTitle('PHP7 is the best');
$booksCollection->addTitle('Laravel Rules');
$booksCollection->addTitle('DHH Rules');

foreach ($booksCollection as $book) {
 var_dump($book);
}

Output

string(15) "Design Patterns"
string(16) "PHP7 is the best"
string(13) "Laravel Rules"
string(9) "DHH Rules"

Another example: As a default behavior in PHP 5, using an object in a foreach structure will traverse all public values. Multiple Iterator classes are available with PHP to allow you to iterate through common lists, such as directories, XML structures and recursive arrays. It's possible to define your own Iterator classes by implementing the Iterator interface, which will override the default behavior. The Iterator interface definition:

interface Iterator
{
 // Returns the current value
 function current();
 
 // Returns the current key
 function key();
 // Moves the internal pointer to the next element
 function next();
 
 // Moves the internal pointer to the first element
 function rewind();
 
 // If the current element is valid (boolean)
 function valid();
}

These methods are all being used in a complete foreach( $object as $key=>$value ) sequence. The methods are executed in the following order:

rewind() 
while valid() {
 current() in $value 
 key() in $key 
 next()
} 
End of Loop

According to Zend, the current() method is called before and after the valid() method.

Implementation in Perl

In Perl, objects providing an iterator interface either overload the <> (iterator operator),[4] or provide a hash or tied hash interface that can be iterated over with each.[5] Both <> and each return undef when iteration is complete. Overloaded <> operator:

# fibonacci sequence
packageFibIter;
useoverload
'<>'=>'next_fib';
subnew{
my$class=shift;
bless{index=>0,values=>[0,1]},$class
}
subnext_fib{
my$self=shift;
my$i=$self->{index}++;
$self->{values}[$i]||=
$i>1?$self->{values}[-2]+$self->{values}[-1]
:($self->{values}[$i]);
}
# reset iterator index
subreset{
my$self=shift;
$self->{index}=0
}
packagemain;
my$iter=FibIter->new;
while(my$fib=<$iter>){
print"$fib","\n";
}

Iterating over a hash (or tied hash):

# read from a file like a hash
packageHashIter;
usebase'Tie::Hash';
subnew{
my($class,$fname)=@_;
my$obj=bless{},$class;
tie%$obj,$class,$fname;
bless$obj,$class;
}

subTIEHASH{
# tie hash to a file
my$class=shift;
my$fname=shiftordie'Need filename';
die"File $fname must exist"
unless[-f$fname];
openmy$fh,'<',$fnameordie"open $!";
bless{fname=>$fname,fh=>$fh},$class;
}
subFIRSTKEY{
# (re)start iterator 
my$self=shift;
my$fh=$self->{fh};
if(notfileno$self->{fh}){
open$fh,'<',$self->{fname}ordie"open $!";
}
# reset file pointer
seek($fh,0,0);
chomp(my$line=<$fh>);
$line
}
subNEXTKEY{
# next item from iterator
my$self=shift;
my$fh=$self->{fh};
returnifeof($fh);
chomp(my$line=<$fh>);
$line
}
subFETCH{
# get value for key, in this case we don't
# care about the values, just return 
my($self,$key)=@_;
return
}
submain;
# iterator over a word file
my$word_iter=HashIter->new('/usr/share/dict/words');
# iterate until we get to abacus
while(my$word=each(%$word_iter)){
print"$word\n";
lastif$wordeq'abacus'
}
# call keys %tiedhash in void context to reset iterator
keys%$word_iter;
Implementation in Python

Python prescribes a syntax for iterators as part of the language itself, so that language keywords such as for work with what Python calls iterables. An iterable has an __iter__() method that returns an iterator object. The "iterator protocol" requires next() return the next element or raise a StopIteration exception upon reaching the end of the sequence. Iterators also provide an __iter__() method returning themselves so that they can also be iterated over; e.g., using a for loop. Generators are available since 2.2.

In Python 3, next() was renamed __next__().[6]

In Python, iterators are objects that adhere to the iterator protocol. You can get an iterator from any sequence (i.e. collection: lists, tuples, dictionaries, sets, etc.) with the iter() method. Another way to get an iterator is to create a generator, which is a kind of iterator. To get the next element from an iterator, you use the next() method (Python 2) / next() function (Python 3). When there are no more elements, it raises the StopIteration exception. To implement your own iterator, you just need an object that implements the next() method (Python 2) / __next__() method (Python 3). Here are two use cases:

# from a sequence
x = [42, "test", -12.34]
it = iter(x)
try:
 while True:
 x = next(it) # in Python 2, you would use it.next()
 print x
except StopIteration:
 pass
# a generator
deffoo(n):
 for i in range(n):
 yield i
it = foo(5)
try:
 while True:
 x = next(it) # in Python 2, you would use it.next()
 print x
except StopIteration:
 pass
Implementation in Raku

Raku provides APIs for iterators, as part of the language itself, for objects that can be iterated with for and related iteration constructs, like assignment to a Positional variable.[7][8] An iterable must at least implement an iterator method that returns an iterator object. The "iterator protocol" requires the pull-one method to return the next element if possible, or return the sentinel value IterationEnd if no more values could be produced. The iteration APIs is provided by composing the Iterable role, Iterator, or both, and implementing the required methods.

To check if a type object or an object instance is iterable, the does method can be used:

say Array.does(Iterable); #=> True
say [1, 2, 3].does(Iterable); #=> True
say Str.does(Iterable); #=> False
say "Hello".does(Iterable); #=> False

The does method returns True if and only if the invocant conforms to the argument type.

Here's an example of a range subroutine that mimics Python's range function:

multi range(Int:D $start, Int:D $end where * <= $start, Int:D $step where * < 0 = -1) {
 (class {
 also does Iterable does Iterator;
 has Int ($.start, $.end, $.step);
 has Int $!count = $!start;

 method iterator { self }
 method pull-one(--> Mu) {
 if $!count > $!end {
 my $i = $!count;
 $!count += $!step;
 return $i;
 }
 else {
 $!count = $!start;
 return IterationEnd;
 }
 }
 }).new(:$start, :$end, :$step)
}

multi range(Int:D $start, Int:D $end where * >= $start, Int:D $step where * > 0 = 1) {
 (class {
 also does Iterable does Iterator;
 has Int ($.start, $.end, $.step);
 has Int $!count = $!start;

 method iterator { self }
 method pull-one(--> Mu) {
 if $!count < $!end {
 my $i = $!count;
 $!count += $!step;
 return $i;
 }
 else {
 $!count = $!start;
 return IterationEnd;
 }
 }
 }).new(:$start, :$end, :$step)
}

my \x = range(1, 5);
.say for x;
# OUTPUT:
# 1
# 2
# 3
# 4

say x.map(* ** 2).sum;
# OUTPUT:
# 30

my \y = range(-1, -5);
.say for y;
# OUTPUT:
# -1
# -2
# -3
# -4

say y.map(* ** 2).sum;
# OUTPUT:
# 30
Implementation in MATLAB

MATLAB supports both external and internal implicit iteration using either "native" arrays or cell arrays. In the case of external iteration where the onus is on the user to advance the traversal and request next elements, one can define a set of elements within an array storage structure and traverse the elements using the for-loop construct. For example,

% Define an array of integers
myArray=[1,3,5,7,11,13];
forn=myArray
% ... do something with n
disp(n)% Echo integer to Command Window
end

traverses an array of integers using the for keyword. In the case of internal iteration where the user can supply an operation to the iterator to perform over every element of a collection, many built-in operators and MATLAB functions are overloaded to execute over every element of an array and return a corresponding output array implicitly. Furthermore, the arrayfun and cellfun functions can be leveraged for performing custom or user defined operations over "native" arrays and cell arrays respectively. For example,

functionsimpleFun
% Define an array of integers
myArray=[1,3,5,7,11,13];
% Perform a custom operation over each element
myNewArray=arrayfun(@(a)myCustomFun(a),myArray);

% Echo resulting array to Command Window 
myNewArray


functionoutScalar=myCustomFun(inScalar)
% Simply multiply by 2
outScalar=2*inScalar;

defines a primary function simpleFun which implicitly applies custom subfunction myCustomFun to each element of an array using built-in function arrayfun.

Alternatively, it may be desirable to abstract the mechanisms of the array storage container from the user by defining a custom object-oriented MATLAB implementation of the Iterator Pattern. Such an implementation supporting external iteration is demonstrated in MATLAB Central File Exchange item Design Pattern: Iterator (Behavioural). This is written in the new class-definition syntax introduced with MATLAB software version 7.6 (R2008a) [9] and features a one-dimensional cell array realisation of the List Abstract Data Type (ADT) as the mechanism for storing a heterogeneous (in data type) set of elements. It provides the functionality for explicit forward List traversal with the hasNext(), next() and reset() methods for use in a while-loop.

References

  1. "Iterators and generators". Retrieved 18 March 2016.
  2. "C# foreach statement".
  3. "PHP: Iterator". Retrieved 23 June 2013.
  4. File handle objects implement this to provide line by line reading of their contents
  5. In Perl 5.12, arrays and tied arrays can be iterated over like hashes, with each
  6. "Python v2.7.1 documentation: The Python Standard Library: 5. Built-in Types". Retrieved 2 May 2011.
  7. "Raku documentation: role Iterable". Retrieved 9 December 2020.
  8. "Raku documentation: role Iterator". Retrieved 9 December 2020.
  9. "New Class-Definition Syntax Introduced with MATLAB Software Version 7.6". The MathWorks, Inc. March 2009. Retrieved September 22, 2009.


👁 Clipboard

To do:
Add more illustrations.


👁 Image
Interpreter
Computer Science Design Patterns
Iterator
Mediator 👁 Image



Ask it here: