Lab
Iterator / generator
type Application = { name: string };
type Page = { applications: Application[]; next: string | null };
// The job board's API for one post: applications, newest first, a page at a time.
// Checker plumbing: the checker builds a board for each case. You don't need to edit it.
class JobBoard {
log: string[] = [];
private pages: Application[][];
constructor(pages: string[][]) {
this.pages = pages.map((page) => page.map((name) => ({ name })));
}
open(): void {
this.log.push('open');
}
// '' asks for the first page; each page's next token asks for the one after it.
fetch(token: string): Page {
const number = token === '' ? 1 : Number(token.slice(1));
this.log.push(`page ${number}`);
const next = number < this.pages.length ? `c${number + 1}` : null;
return { applications: this.pages[number - 1], next };
}
close(): void {
this.log.push('close');
}
}
// The one traversal both callers should share. Not written yet: it yields nothing.
function* applications(board: JobBoard): Generator<Application> {}
// The review screen's first view: the newest `count` applications.
function newest(board: JobBoard, count: number): string[] {
board.open();
const all: string[] = [];
let token: string | null = '';
while (token !== null) {
const page = board.fetch(token);
for (const application of page.applications) all.push(application.name);
token = page.next;
}
board.close();
return all.slice(0, count);
}
// The search box: has this person applied?
function hasApplied(board: JobBoard, name: string): boolean {
board.open();
let token: string | null = '';
while (token !== null) {
const page = board.fetch(token);
if (page.applications.length === 0) break; // nothing left
for (const application of page.applications) {
if (application.name === name) return true;
}
token = page.next;
}
board.close();
return false;
}