Skip to content

Instantly share code, notes, and snippets.

@tw3
Last active February 18, 2022 14:47
Show Gist options
  • Save tw3/b6354bae2d4170fc72022f741ea5bb24 to your computer and use it in GitHub Desktop.
Save tw3/b6354bae2d4170fc72022f741ea5bb24 to your computer and use it in GitHub Desktop.
Rotates the starting index and ending index when looping over an array multiple times. At any given point you have the option to reset the starting index and have the array loop to the first item after reaching the end of the array(resetAtNextIndex()). Example usage can be found here: https://stackblitz.com/edit/typescript-cfxmnn?file=index.ts
export class RotatingIterator<T> implements Iterable<T> {
private readonly origStart: number;
private nextIndex: number;
private isDone: boolean;
private hasLooped: boolean;
constructor(private readonly arr: T[], private startIndex = 0) {
this.origStart = startIndex;
this.nextIndex = startIndex;
this.isDone = false;
this.hasLooped = false;
}
[Symbol.iterator]() {
return this;
}
get length(): number {
return this.arr.length;
}
next(): IteratorResult<T> {
if (!this.isDone) {
// We may not be done yet
if (!this.hasLooped) {
// We have not yet looped
if (this.isBeforeEndLoop()) {
return this.getNextResult();
}
// We need to loop
this.hasLooped = true;
this.nextIndex = 0;
}
// We have looped and may not have reached the start
if (this.isBeforeStart()) {
return this.getNextResult();
}
// We have looped and come back to the start
this.isDone = true;
}
// We are done
return this.getDoneResult();
}
resetAtNextIndex(): void {
this.startIndex = this.nextIndex;
this.isDone = false;
this.hasLooped = false;
}
resetAtOriginalStartIndex(): void {
this.startIndex = this.origStart;
this.isDone = false;
this.hasLooped = false;
}
getValueByIndex(idx: number): T {
return idx < this.arr.length ? this.arr[idx] : undefined;
}
private getNextResult(): IteratorResult<T> {
const result: IteratorResult<T> = {
index: this.nextIndex,
value: this.arr[this.nextIndex],
done: false,
};
// console.log({ this.nextIndex });
this.nextIndex++;
return result;
}
private getDoneResult(): IteratorResult<T> {
return {
index: undefined,
value: undefined,
done: true,
};
}
private isBeforeStart(): boolean {
return this.nextIndex < this.startIndex;
}
private isBeforeEndLoop(): boolean {
return this.nextIndex < this.arr.length;
}
}
export interface IteratorResult<T> {
index: number;
value: T;
done: boolean;
}
@tw3
Copy link
Author

tw3 commented Feb 18, 2022

For example given an array like this: [0, 1, 2, 3, 4]

  • Iterate 3 times and stop => accesses items 0, 1, 2
  • Then, call resetAtNextIndex() & iterate 4 more times and stop => accesses items 3, 4, 0, 1
  • Then, call resetAtNextIndex() & iterate until "done" => accesses 2, 3, 4, 0, 1
  • Then, iterate until "done" => will do nothing (b/c it is already done and hasn't been reset)
  • Then, call resetAtNextIndex() & iterate 2 more times => accesses 2, 3
  • Then, iterate until "done" => accesses 4, 0, 1

Seen here: https://stackblitz.com/edit/typescript-efw6th?file=index.ts

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment