AI InterviewSearch…Search problems, topics, or pages…Ctrl KGet started
Skip to content

06 Collections and iteration / Checkpoint

Checkpoint — Collections and iteration

24 min · +25 XP · 3 exercises · 12 questions

Exercises0/3
Quiz · 70% to clear12 q

This checkpoint covers Map and Set (operations, SameValueZero, insertion order, the idioms and hand-written set algebra), the weak collections and why they cannot be iterated, the iteration protocol (Symbol.iterator, next(), done/value, laziness, return()), generators (yield, yield*, next(value), lazy pipelines), and symbols as keys and as the language's hooks.

How it works. Twelve questions and three programs; 70% on the questions and every program accepted clears the module.

Before you start, make sure you can answer:

  • Map versus object; how Map compares keys; how to count, group and index with a Map.
  • Why a WeakMap has no size and takes only object keys; the three patterns it exists for.
  • The exact shape of an iterator; iterable versus iterator; what break triggers.
  • What runs when a generator is called, what yield* does, why the first next(v) argument is dropped.
  • Symbol() versus Symbol.for(); which enumeration paths skip symbol keys; three well-known symbols.

The programs are an LRU cache built on a Map's insertion order, a graph explorer with adjacency sets and a breadth-first generator, and a small iterator toolkit — chunk, zip, enumerate, takeWhile — driven by commands.

Common questions

What is the exact shape of a JavaScript iterator?

An iterator is an object with a next() method that returns { value, done }: done: false with each value, then done: true once the sequence ends. It may also have an optional return() method, which break calls so the iterator can clean up.

Why is the argument to a generator's first next() ignored?

Calling a generator runs none of its body. The first next() starts it and runs to the first yield, so there is no paused yield to receive the argument, and it is dropped. Values sent with later next(v) calls become the results of the yield expressions.

Why does a WeakMap have no size and take only object keys?

Its entries disappear when their keys are garbage collected, and collection must not be observable, so there is no size and no iteration. Keys must be objects because a primitive can never become unreachable, so holding one weakly would mean nothing.

JavaScript Map, Set, Iterators and Generators Practice Quiz

Test JavaScript collections and iteration with 12 questions and three programs: Map and Set, WeakMap, the iteration protocol, generators and symbols.

  • Course: JavaScript study plan
  • Module: Collections and iteration
  • Kind: Checkpoint — cleared at 70%
  • Reading time: 24 min
  • Runtime: Node 16

Checkpoint — Collections and iteration is the checkpoint that closes the Collections and iteration module: a graded quiz and whole-program exercises, passed at 70%.

Instructions

This checkpoint covers Map and Set (operations, SameValueZero, insertion order, the idioms and hand-written set algebra), the weak collections and why they cannot be iterated, the iteration protocol (Symbol.iterator, next(), done/value, laziness, return()), generators (yield, yield*, next(value), lazy pipelines), and symbols as keys and as the language's hooks.

How it works. Twelve questions and three programs; 70% on the questions and every program accepted clears the module.

Before you start, make sure you can answer:

  • Map versus object; how Map compares keys; how to count, group and index with a Map.
  • Why a WeakMap has no size and takes only object keys; the three patterns it exists for.
  • The exact shape of an iterator; iterable versus iterator; what break triggers.
  • What runs when a generator is called, what yield* does, why the first next(v) argument is dropped.
  • Symbol() versus Symbol.for(); which enumeration paths skip symbol keys; three well-known symbols.

The programs are an LRU cache built on a Map's insertion order, a graph explorer with adjacency sets and a breadth-first generator, and a small iterator toolkit — chunk, zip, enumerate, takeWhile — driven by commands.

Common questions

What is the exact shape of a JavaScript iterator?

An iterator is an object with a next() method that returns { value, done }: done: false with each value, then done: true once the sequence ends. It may also have an optional return() method, which break calls so the iterator can clean up.

Why is the argument to a generator's first next() ignored?

Calling a generator runs none of its body. The first next() starts it and runs to the first yield, so there is no paused yield to receive the argument, and it is dropped. Values sent with later next(v) calls become the results of the yield expressions.

Why does a WeakMap have no size and take only object keys?

Its entries disappear when their keys are garbage collected, and collection must not be observable, so there is no size and no iteration. Keys must be objects because a primitive can never become unreachable, so holding one weakly would mean nothing.

Exercises

An LRU cache on Map order

Implement LRUCache(capacity) over a private Map whose insertion order is the recency order (oldest first). get(key) returns the value (re-inserting the entry so it becomes newest) or -1; put(key, value) inserts or refreshes, then evicts the oldest entry when over capacity and returns the evicted key (else null); get size; entries() yields entries newest first. Line 1 is the capacity; then put k v (print evict <k> when something was evicted), get k (print get <k> -> <v|-1>), show (print [k=v, ...] size=<n> newest first).

Example: capacity 2, then put a 1, put b 2, get a, put c 3, get b, show, put a 10, show →

get a -> 1
evict b
get b -> -1
[c=3, a=1] size=2
[a=10, c=3] size=2

A graph explorer with a breadth-first generator

Store an undirected graph as a Map from node to a Set of neighbours. Write a generator bfs(start) yielding [node, distance, parent] in breadth-first order, visiting neighbours in sorted order and each node once. Commands: edge a b; bfs a prints bfs a: <node@distance ...>; path a b reconstructs the shortest path from the parents (stop pulling from the generator as soon as b appears) and prints path a -> b: <nodes> (<n> hops) or path a -> b: none; degree a prints degree a = <neighbour count> (0 for an unknown node).

Example: edges a b, a c, b d, c d, d e, f g, then bfs a, path a e, path a g, degree d →

bfs a: a@0 b@1 c@1 d@2 e@3
path a -> e: a b d e (3 hops)
path a -> g: none
degree d = 3

An iterator toolkit

Write four generators that work on any iterable: chunk(it, size) (arrays of size, the last possibly shorter), zip(...its) (arrays of the i-th items, stopping at the shortest), enumerate(it, start = 0) ([index, item] pairs) and takeWhile(pred, it). Input: line 1 numbers a, line 2 words b, line 3 a chunk size, line 4 a limit. Print chunks=<chunk(a, size)>, zip=<zip(a, b)>, enumerate=<enumerate(b, 1)>, takeWhile=<takeWhile(x => x < limit, a)> (all as JSON), then zipString=<zip("abc", a) as c+n pairs joined by ,>.

Example: 1 2 3 4 5 6 7 / red green blue / 3 / 5 →

chunks=[[1,2,3],[4,5,6],[7]]
zip=[[1,"red"],[2,"green"],[3,"blue"]]
enumerate=[[1,"red"],[2,"green"],[3,"blue"]]
takeWhile=[1,2,3,4]
zipString=a1,b2,c3

In this module: Collections and iteration

← Symbols — unique keys and the language's extension points · throw, try, catch, finally — the mechanics, precisely →