17. Demultiplex an Interleaved Multi-Context Audio Stream
context_id to group streamed word chunks into one continuous utterance for prosody (docs.cartesia.ai realtime text-to-speech quickstart). This problem builds the demultiplexing step a client needs: split chunks that arrive interleaved across contexts back into one ordered stream per context_id.Problem
A single WebSocket connection can carry many independent contexts at once, each a continuous full-duplex stream. On the wire, chunks for different contexts arrive interleaved on that one connection. A client needs to demultiplex them back into one correctly-ordered stream per context_id before it can play or process any single context.
Given a list of (context_id, seq, payload) triples — interleaved across contexts, and possibly out of order both across and within a context — return a dict mapping each context_id to its payloads, ordered by seq ascending.
Source: src/17_context_demux.py
def demux_by_context(chunks: list[tuple[str, int, str]]) -> dict[str, list[str]]:
>>> demux_by_context([("a", 1, "lo"), ("b", 0, "wor"), ("a", 0, "hel"), ("b", 1, "ld")])
{'a': ['hel', 'lo'], 'b': ['wor', 'ld']}
>>> demux_by_context([])
{}
Step-by-Step Approach
- Make a single pass over
chunksand group them bycontext_idinto adict[str, list[tuple[int, str]]], usingsetdefault(context_id, []).append((seq, payload))so a first-seen context lazily gets an empty list. - This grouping pass alone doesn't guarantee order within a context — the problem statement explicitly allows chunks to be out of order within a context too, not just across contexts.
- For each context's list of
(seq, payload)pairs, sort byseq. Tuple comparison sorts by the first element (seq) automatically, so plainsorted(items)is enough — no custom key function needed. - Extract just the payload from each sorted
(seq, payload)pair to build the final per-context list, discarding the sequence numbers now that ordering has been applied. - Return the dict mapping each
context_idto its ordered payload list; dict comprehension does the grouping-to-final-shape conversion in one expression.
The key insight is splitting this into two clean phases — group first, then sort each group independently — rather than trying to maintain sorted order incrementally while grouping; since each context's chunk count is typically small relative to the whole interleaved stream, sorting each group separately is both simpler and no worse asymptotically than a single global sort by (context_id, seq).
Reference solution
def demux_by_context(chunks: list[tuple[str, int, str]]) -> dict[str, list[str]]:
# group by context_id first (O(n)), preserving first-seen context order
groups: dict[str, list[tuple[int, str]]] = {}
for context_id, seq, payload in chunks:
groups.setdefault(context_id, []).append((seq, payload))
# then sort each group's (seq, payload) pairs by seq -- handles chunks that
# arrive out of order within a context too, not just across contexts
return {cid: [payload for _, payload in sorted(items)] for cid, items in groups.items()}
Key Functions & Tricks
dict.setdefault(key, []).append(...)— lazily creates a new context's list and appends to it in one expression.sorted(items)— sorts a list of (seq, payload) tuples by seq automatically, since tuple comparison compares element-by-element.dict comprehension over groups.items()— converts the grouped-and-sorted intermediate structure into the final {context_id: [payloads]} shape in one line.tuple unpacking in the for loop— destructures each (context_id, seq, payload) triple directly in the loop header.
How to Recognize This Pattern
Reach for group-then-sort whenever a problem describes a single stream that actually interleaves multiple independent logical sequences distinguished by some id/key, and asks you to recover each sequence in its own order — multiplexed network protocols, log lines from multiple concurrent requests sharing one file, or parallel worker output merged into one stream are all this shape. The tell is an id field plus an explicit ordering field (here, seq) traveling together on each record. A common variation only needs one context's stream extracted, not all of them, in which case filtering before grouping avoids wasted work on contexts you don't care about. A common pitfall is assuming input arrives already in order per context (skipping the sort) just because it's typically close to ordered in practice — that works until one retried or delayed chunk breaks it, so the explicit sort is what makes the solution correct under the full out-of-order guarantee the problem statement actually makes.