Skip to main content

Iterator Pattern

Access elements sequentially without exposing underlying structure

Pattern Overview

πŸ”„ Iterator Pattern

The Iterator Pattern provides a way to access elements of a collection sequentially without exposing the underlying representation. It separates the traversal logic from the collection structure.

Core Concepts

πŸ”Ή Iterator Interface - Defines methods for traversing elements (hasNext, next, reset)
πŸ”Ή Concrete Iterator - Implements traversal logic for specific collections
πŸ”Ή Iterable Interface - Collection that can create iterators
πŸ”Ή External Iteration - Client controls iteration process

Real-World Applications

Data Structures - Arrays, lists, trees, graphs with different traversal strategies File Systems - Directory traversal with various filtering and ordering options Database Results - Process query results without loading all data into memory Streaming Data - Process large datasets one element at a time

Traversal Strategies

Linear Collections - Forward, reverse, filtered iteration Tree Structures - Pre-order, post-order, level-order traversal Custom Logic - Skip elements, transform values, conditional processing Lazy Evaluation - Generate elements on-demand without storing entire collection

Implementation Benefits

βœ… Encapsulation - Internal structure hidden from client code
βœ… Multiple traversals - Different iterators can traverse same collection
βœ… Uniform interface - Same iteration pattern across different data structures
βœ… Memory efficiency - Process large collections without loading everything

Examples:
Iterate through book library with different filtering strategies without exposing internal structure
Input:
const library = createBookLibrary();

console.log('All books:');
iteratorForEach(library.createIterator(), book => 
  console.log(book.toString())
);

console.log('\nDystopian books:');
iteratorForEach(library.createGenreIterator('Dystopian'), book => 
  console.log(book.toString())
);

console.log('\nReverse order:');
const reverseBooks = iteratorCollect(library.createReverseIterator());
console.log(reverseBooks.slice(0, 3).map(b => b.title).join(', '));
Output:
All books:
"1984" by George Orwell (1949)
"Brave New World" by Aldous Huxley (1932)
"The Hobbit" by J.R.R. Tolkien (1937)
...

Dystopian books:
"1984" by George Orwell (1949)
"Brave New World" by Aldous Huxley (1932)

Reverse order:
Neuromancer, Foundation, Dune
Traverse file system tree using different algorithms without exposing tree structure
Input:
const tree = createFileSystemTree();

console.log('Pre-order traversal:');
const preOrder = iteratorCollect(tree.createPreOrderIterator());
console.log(preOrder.slice(0, 5).join(' β†’ '));

console.log('\nLevel-order traversal:');
const levelOrder = iteratorCollect(tree.createLevelOrderIterator());
console.log(levelOrder.slice(0, 5).join(' β†’ '));
Output:
Pre-order traversal:
root/ β†’ src/ β†’ index.js β†’ utils.js β†’ lib/

Level-order traversal:
root/ β†’ src/ β†’ lib/ β†’ test/ β†’ package.json
Generate numeric sequences with different patterns using iterator interface
Input:
const ranges = createNumberRanges();

console.log('Standard range (1-10):');
console.log(iteratorCollect(ranges.standard.createIterator()).join(', '));

console.log('\nEven numbers (0-20, step 2):');
console.log(iteratorCollect(ranges.step2.createEvenIterator()).join(', '));

console.log('\nReverse range (5 to -5):');
console.log(iteratorCollect(ranges.negative.createReverseIterator()).join(', '));
Output:
Standard range (1-10):
1, 2, 3, 4, 5, 6, 7, 8, 9, 10

Even numbers (0-20, step 2):
0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20

Reverse range (5 to -5):
-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5

Concepts

design patternssoftware architecturecode organizationobject-oriented programming

Complexity Analysis

Time:O(n)
Space:O(1)

Implementation

book-collection

Time: O(n) | Space: O(1)
// Book collection with filtered iteration
class Book {
  constructor(
    public title: string,
    public author: string,
    public year: number,
    public genre: string
  ) {}

  toString(): string {
    return `"${this.title}" by ${this.author} (${this.year})`;
  }
}

class BookCollection implements Iterable<Book> {
  private books: Book[] = [];

  addBook(book: Book): void {
    this.books.push(book);
  }

  createIterator(): Iterator<Book> {
    return new BookIterator(this.books);
  }

  createGenreIterator(genre: string): Iterator<Book> {
    return new GenreFilterIterator(this.books, genre);
  }

  createReverseIterator(): Iterator<Book> {
    return new ReverseBookIterator(this.books);
  }
}

class BookIterator implements Iterator<Book> {
  private index = 0;

  constructor(private books: Book[]) {}

  hasNext(): boolean {
    return this.index < this.books.length;
  }

  next(): Book | null {
    if (this.hasNext()) {
      return this.books[this.index++];
    }
    return null;
  }

  reset(): void {
    this.index = 0;
  }
}

Β© 2025 John Dilig. Built with Next.js & TypeScript. Open Source (MIT) β€’ Wiki

v... β€’ Auto-versioned