-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathIterator.ts
148 lines (118 loc) · 3.24 KB
/
Iterator.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
/**
* Iterator Design Pattern
*
* Intent: Lets you traverse elements of a collection without exposing its
* underlying representation (list, stack, tree, etc.).
*/
interface Iterator<T> {
// Return the current element.
current(): T;
// Return the current element and move forward to next element.
next(): T;
// Return the key of the current element.
key(): number;
// Checks if current position is valid.
valid(): boolean;
// Rewind the Iterator to the first element.
rewind(): void;
}
interface Aggregator {
// Retrieve an external iterator.
getIterator(): Iterator<string>;
}
/**
* Concrete Iterators implement various traversal algorithms. These classes
* store the current traversal position at all times.
*/
class AlphabeticalOrderIterator implements Iterator<string> {
private collection: WordsCollection;
/**
* Stores the current traversal position. An iterator may have a lot of
* other fields for storing iteration state, especially when it is supposed
* to work with a particular kind of collection.
*/
private position: number = 0;
/**
* This variable indicates the traversal direction.
*/
private reverse: boolean = false;
constructor(collection: WordsCollection, reverse: boolean = false) {
this.collection = collection;
this.reverse = reverse;
if (reverse) {
this.position = collection.getCount() - 1;
}
}
public rewind() {
this.position = this.reverse ? this.collection.getCount() - 1 : 0;
}
public current(): string {
return this.collection.getItems()[this.position];
}
public key(): number {
return this.position;
}
public next(): string {
const item = this.collection.getItems()[this.position];
this.position += this.reverse ? -1 : 1;
return item;
}
public valid(): boolean {
if (this.reverse) {
return this.position >= 0;
}
return this.position < this.collection.getCount();
}
}
/**
* Concrete Collections provide one or several methods for retrieving fresh
* iterator instances, compatible with the collection class.
*/
class WordsCollection implements Aggregator {
private items: string[] = [];
public getItems(): string[] {
return this.items;
}
public getCount(): number {
return this.items.length;
}
public addItem(item: string): void {
this.items.push(item);
}
public getIterator(): Iterator<string> {
return new AlphabeticalOrderIterator(this);
}
public getReverseIterator(): Iterator<string> {
return new AlphabeticalOrderIterator(this, true);
}
}
/**
* The client code may or may not know about the Concrete Iterator or Collection
* classes, depending on the level of indirection you want to keep in your
* program.
*/
const collection = new WordsCollection();
collection.addItem('First');
collection.addItem('Second');
collection.addItem('Third');
const iterator = collection.getIterator();
console.log('Straight traversal:');
while (iterator.valid()) {
console.log(iterator.next());
}
console.log('');
console.log('Reverse traversal:');
const reverseIterator = collection.getReverseIterator();
while (reverseIterator.valid()) {
console.log(reverseIterator.next());
}
/** OUTPUT
Straight traversal:
First
Second
Third
Reverse traversal:
Third
Second
First
* */