If mapping a course returns a list of terms, each term a list of sessions, why does one flatten not reach the sessions?
answer
- depth is a number, count it
- the collapse never looks inside
- one level per flatten
- k one-to-many stages need k collapses
- recursive deep collapse is a different operation
basics
~10 sFlattening removes exactly one level of nesting, not all of it. Collapsing the per-course level leaves a list of term-lists; reaching the sessions needs a second collapse, one per level of structure.
solid answer
~50 sFlattening is defined as concatenating the inner structures of a structure of structures, which lowers the depth by exactly one and never looks deeper. Start at depth three - courses, then terms, then sessions - and one collapse gets you to depth two: a list of term-lists whose course grouping is gone but whose term grouping is untouched. A second collapse reaches the flat session list. The rule worth stating out loud is one collapse per level of nesting, so a chain of *k* one-to-many stages needs *k* of them - which is why each stage carries its own collapse instead of deferring one big flatten to the end. A collapse that recurses until nothing nested remains is a different operation, with a depth that depends on the data rather than on the step you wrote.
code
pseudocode · 9 linesbyCourse = [ [ [s1, s2], [s3] ], // course A: two terms
[ [s4] ] ] // course B: one term
// depth 3: courses -> terms -> sessions
once = flatten(byCourse)
// [ [s1, s2], [s3], [s4] ] depth 2: the course level is gone
twice = flatten(once)
// [s1, s2, s3, s4] depth 1: the flat session listgo deeper
Learn to count depth: each container between the outside and an element is one level, and one flatten removes exactly one of them.
Explain why a collapse only touches the structures directly under the root, and why k one-to-many stages therefore need k collapses.
Recognise the review symptoms of a missing collapse - a stage opening what it thought was an element, a count off by a grouping level - and fix it at the stage that added the level.
Rule on whether a shared pipeline collapses per stage or preserves intermediate grouping, since that choice decides what every downstream consumer can still reconstruct.
## Depth is what is being counted Talking about this precisely needs one word: **depth**, the number of levels of container between the outside and an element. A list of sessions has depth one. A list of courses, each holding a list of sessions, has depth two. A list of courses, each holding a list of terms, each holding a list of sessions, has depth three. Two facts settle everything else: - a mapping step whose function returns a structure **adds one** to the depth, because the returned structure lands whole in a slot; - a flatten **removes one**, by concatenating the structures directly under the root. Neither operation looks any deeper than that. ## One collapse, one level Start at depth three and apply a single flatten: - before: `[ [ [s1, s2], [s3] ], [ [s4] ] ]`, depth three; - after: `[ [s1, s2], [s3], [s4] ]`, depth two. The **course** grouping is gone: term lists that were split across two courses now sit side by side under one root. The **term** grouping is untouched, because the flatten never looked inside the elements it moved - it only concatenated the structures directly under the root. Reaching the sessions needs a second collapse, which gives `[s1, s2, s3, s4]` at depth one. So: **one collapse per level of nesting**. A chain of *k* one-to-many stages produces depth *k* + 1 counting the container you started with, and needs *k* collapses to come back to flat. ## Why each stage carries its own collapse Given that arithmetic you could imagine writing *k* mapping stages and then *k* flattens at the end. Nobody does, for three reasons: 1. **The intermediate shapes are unusable.** Between stages you would hold a value of growing depth, and every stage after the first would have to reach through that depth to find the element it actually wants. 2. **The depth is part of the shape.** Each extra level changes what the next stage and the final consumer must accept, so adding a stage edits the whole pipeline rather than appending to it. 3. **Nothing is gained.** Collapsing per stage keeps the running depth at one from beginning to end; deferring the collapses builds a structure only to dismantle it. Bind *is* that per-stage discipline: map the element to a structure, collapse the level you just added, hand the next stage a flat structure again. | after | mapping stages only | bind stages | |---|---|---| | stage 1 | depth 2 | depth 1 | | stage 2 | depth 3 | depth 1 | | stage 3 | depth 4 | depth 1 | | left to do | three collapses | none | ## A recursive deep collapse is a different operation Some collection libraries also offer a collapse that keeps going until nothing nested remains. It is genuinely useful for ragged data, but it is not the default, for two reasons: - **Its depth is data-dependent.** It removes as many levels as the values happen to have, so the result shape depends on the data rather than on the step you wrote. Its result type is awkward to state in several type systems and cannot be stated in some of them without extra machinery. - **It destroys grouping you may have wanted.** If the term level was meaningful, a deep collapse takes it away along with the course level, and no later stage can tell which term a session belonged to. The one-level collapse is the honest default precisely because it removes an amount of structure you can see in the code. ## The symptom in review The mistake rarely announces itself as *wrong depth*. It shows up as a stage further down that opens something it expected to be an element; as a count that is off by a whole grouping level; as a signature with two containers in it where the author meant one; or as a function that quietly loops one extra time to make the shape work. The check is arithmetic: count the stages that return a structure, count the collapses, and make sure the two numbers agree.
- What does a chain of two bind stages do to the depth?It holds it at one. Each bind maps an element to a structure - which would take the depth to two - and immediately collapses that level back, so the running value between stages is always flat. A pipeline of any number of one-to-many stages therefore keeps the same shape throughout instead of growing one level per stage.
- Why is a recursive deep collapse rarely the default operation?Because the number of levels it removes depends on the values rather than on the code, so the result shape is not visible in the step you wrote and is awkward to give a type. It also flattens away intermediate grouping that may have been meaningful, and that grouping cannot be reconstructed afterwards unless each element still names its group.
saying these in an interview costs you the question
- Says one flatten always produces a fully flat result
- Thinks the collapse recurses into the elements it moves
- Expects one collapse at the end to undo three nesting stages
- Treats a recursive deep collapse as the same operation
- Cannot say what depth a pipeline holds between two stages