If a mapping step returns a list of sessions per course, what shape does the pipeline hold before flattening?
answer
- count the layers, not the items
- one output slot per input element
- the grouping survives the map
- an empty inner list still takes a slot
- flatten concatenates in order
basics
~20 sA list of lists: one inner list of sessions per course, in course order, with an empty inner list wherever a course scheduled nothing. Flattening one level concatenates those inner lists into a single list of sessions.
solid answer
~40 sElement-wise mapping preserves the shape of the outer structure: one output slot per input element. If the function you hand it returns a list of sessions, the result is a list of lists - exactly one inner list per course, in the same order, including empty inner lists for the courses that scheduled nothing. The sessions are all present, but they are still grouped one level deep, so anything that wants sessions has to open every inner list first. Flattening one level concatenates those inner lists, in order, into a single list of sessions. `bind` is just those two steps fused into one operation, which is why its result length is the sum of the inner lengths rather than the number of courses.
code
pseudocode · 13 linescourses = [A, B, C]
sessionsOf(A) = [a1, a2]
sessionsOf(B) = []
sessionsOf(C) = [c1, c2]
grouped = map(courses, course -> sessionsOf(course))
// [[a1, a2], [], [c1, c2]] outer length 3, one slot per course
flat = flatten(grouped)
// [a1, a2, c1, c2] length 4, the sum of the inner lengths
same = bind(courses, course -> sessionsOf(course))
// [a1, a2, c1, c2] the two steps fused into onego deeper
Recall the shape rule: one output slot per input element. If the function returns a list, you are holding a list of lists until something flattens it.
Explain why the outer length is pinned to the input length, and what the empty inner list means for a course that scheduled nothing.
Catch the shape mistake in review: a count that matches the course total when somebody asked for sessions, or a stage looping over what it assumed was flat.
Decide when the grouping is the product. Flattening is lossy, so a flat feed usually forces every element to carry the identity of the group it came from.
## What a mapping step actually promises Element-wise mapping is **shape-preserving**. Give it a structure of *n* elements and a function `f`, and you get back a structure of *n* elements, in the same order, where slot *i* holds `f(element_i)`. That promise says nothing at all about what `f` returns - only that whatever it returns lands whole in one slot of the result. So when `f` is *give me this course's scheduled sessions*, and a course may have four sessions, one, or none, the result is not a list of sessions. It is a **list of lists of sessions**: - exactly one inner list per course, never more and never fewer; - in the same order as the courses; - with an **empty inner list** sitting in the slot of every course that scheduled nothing. Nothing is lost and nothing is invented. The sessions are all there, but they are still **grouped one level deep**, so any later stage - counting sessions, sorting them by start time, selecting the weekend ones - has to open every inner list before it can see a single session. Written as loops, that is a loop inside a loop, and each further one-to-many stage adds another layer. ## Flattening one level Flattening takes a structure whose elements are themselves structures and concatenates the inner ones, in order, into a single structure one level shallower. `[[a, b], [], [c]]` becomes `[a, b, c]`. Two properties are routinely stated wrongly: 1. **It concatenates; it does not merge, sort or de-duplicate.** If two courses both list a shared session, that session appears twice in the flat result. Removing duplicates is a separate step you have to ask for. 2. **It removes exactly one level.** A structure nested three deep flattens to two deep, not to flat. **Transform-then-flatten** - the operation usually called **bind** - is the mapping step and the one-level flatten fused into a single traversal. The result is indistinguishable from doing them in sequence; the fusion matters because it is the composable unit, and because a pipeline built from it never has to name the intermediate structure of structures at all. ## What the counts do | | element-wise mapping | transform-then-flatten | |---|---|---| | result shape | structure of structures | flat structure | | result length | the number of courses | the sum of the per-course session counts | | a course with no sessions | contributes an empty inner structure | contributes nothing | | a course with four sessions | contributes one inner structure | contributes four elements | | order | course order preserved | course order preserved, one course's sessions kept adjacent | The length row is the one interviewers push on. Under mapping the outer length is pinned to the input length, so a course with nothing scheduled still occupies a slot. Under transform-then-flatten the output length is decoupled from the input length entirely: it may be larger, smaller, or zero. ## Reading the shape off the signature You never have to guess which of the two you are holding. If the structure holds `T` and the function you passed has the shape `T -> Structure<U>`: - mapping gives `Structure<Structure<U>>`; - one flatten gives `Structure<U>`; - bind gives `Structure<U>` in a single step. The usual tells that you wanted the second are a stage further down that starts by looping over something it expected to be flat, and a count that comes out equal to the number of courses when somebody asked how many sessions there are. ## Flattening is a choice, not a cleanup Sometimes the grouping *is* the answer. A catalogue page that renders each course with its own session list needs the structure of structures; flattening throws away the only thing that says which sessions belong together. The rule of thumb: flatten when every session is treated alike downstream, keep the nesting when the boundary between groups carries meaning. And note the asymmetry. Grouped to flat is cheap and always available. Flat back to grouped is not - once the inner lists are concatenated, nothing in the result records which course a session came from unless the session already carries that identity. That is why a flattened feed so often grows an extra field on its element type: the group key that somebody has to put back by hand.
- What happens to the empty inner list when the result is flattened?It contributes nothing. Flattening concatenates the inner structures, and concatenating an empty one adds no elements, so a course that scheduled nothing simply vanishes from the flat result. That is why the flat length is the sum of the inner lengths, and can be smaller than the number of courses - or zero, if every course is empty.
- When is keeping the list of lists the better outcome?Whenever the boundary between groups carries meaning: rendering each course with its own session list, counting sessions per course, or applying a per-course rule. Flattening is lossy in one direction - once the inner lists are concatenated, nothing says which course a session came from unless each session already carries that identity.
Each course hands you its own printed session sheet, and some sheets come back blank. Mapping leaves you holding the stack of sheets; flattening is retyping every line onto one continuous list.
saying these in an interview costs you the question
- Says mapping returns the sessions themselves, not lists of them
- Thinks a course with no sessions disappears from the mapped result
- Believes flattening de-duplicates a session listed by two courses
- Reports the mapped result's length as the session count
- Assumes flattening reorders sessions instead of concatenating in order
- Treats the nesting as a bug rather than mapping keeping its promise