skip to content

Numbering Rows Inside a Group

Numbering the rows inside each group by an ordering you pick, then keeping the top few or carrying a total down them. What ties receive is what decides which rows survive.

on this pageshow

questions

4

Rows in each group are numbered by descending amount and the top three kept — how does the tie disposition change which rows survive?

level: middleimportance: must knowfreq 72%

answer

  1. the ordering cannot separate equal rows
  2. distinct numbers versus shared numbers
  3. a gap consumed, or no gap
  4. more than three rows out of a cut at three
  5. which tied row survives is arbitrary

basics

~20 s

It decides both how many rows survive and which ones. Distinct consecutive numbers keep exactly three but pick arbitrarily among tied rows; shared numbers keep every row tied at the cut, so a group can return four or more.

solid answer

~50 s

Three dispositions for equal amounts give three different answers. Give every row a distinct consecutive number and the cut keeps exactly three rows — but which of two tied rows got the lower number was settled by something outside the ordering you stated, so the survivor is arbitrary. Let tied rows share a number and resume after the gap the tie consumed (10, 10, 9, 9 becomes 1, 1, 3, 3) and all four clear a cut at three. Let tied rows share a number and continue without a gap and the cut keeps the rows of the top three *distinct* amounts, however many rows that is. So decide the policy first: exactly three rows, all rows tied at the boundary, or the top three distinct values. Tools default differently and some offer only the first form, so state it rather than inherit it.

go deeper

for a junior

Know that equal values under the chosen ordering are a real case and that what they receive is a setting, not a fact of nature. Being able to say a cut can return more than three rows is already enough here.

for a middle

Work the three dispositions through a concrete group and state the row count each produces. Say which one guarantees a fixed size and what it gives up to get it.

for a senior

Demonstrate that you pick the disposition from what the consumer needs and assert the row count afterwards. Treat an arbitrary survivor on a record that gets acted on as a defect, and remove the tie instead.

for a principal

The judgment is whether your team standardises one disposition or requires it stated per call, and what you owe consumers of a variable-size result when fairness forbids a fixed one.

## Why the tie is the whole question Keeping the top few of each group is two steps: give each row a position inside its group under an ordering you chose, then keep the rows whose position is at or below a cut. Everything interesting happens when two rows of the same group are **equal under that ordering**. The ordering cannot separate them, so something else must, and what that something else is changes both the row count of the result and which specific rows are in it. A grouped operation — one pass that keys every row, computes per key and reassembles — is deterministic about group membership. It is not automatically deterministic about ties, and candidates who have only ever written the happy path assume it is. ## The three dispositions, on one group Take one group whose amounts, descending, are **10, 10, 9, 9** and a cut at three. | Disposition | Numbers produced | Rows surviving a cut at 3 | |---|---|---| | every row gets a distinct consecutive number | 1, 2, 3, 4 | exactly 3 — but which 10 and which 9 is arbitrary | | tied rows share a number, the next value resumes after the gap | 1, 1, 3, 3 | 4 — both 9s carry 3 and clear the cut | | tied rows share a number, the next value continues with no gap | 1, 1, 2, 2 | 4 — the top two distinct amounts, all their rows | A fourth form exists in some tools: the tied rows each receive the average of the positions they would have occupied, producing fractional values. It is used when the number is going to be analysed rather than compared against a cut, and it makes a cut behave awkwardly. Three consequences are worth stating plainly: 1. **Only distinct consecutive numbering guarantees a fixed row count** — at most the cut, or the whole group if it is smaller. It buys that guarantee by breaking the tie with something you did not specify. 2. **The shared-number forms can return more than the cut**, but only when a tie straddles or sits exactly at the cut. A tie further down the group changes nothing. 3. **The no-gap form changes what the cut means.** It stops being *the top three rows* and becomes *the rows of the top three distinct values*, which on a column with few distinct values can be most of the group. ## What arbitrary really means Under distinct consecutive numbering the surviving row among a tie was chosen by whatever order those rows were already sitting in when the numbering ran. That is not a property of your data and it is not promised to you: a different read, a rewritten earlier step, or a different execution of the same pipeline can hand back a different survivor with no change to the amounts. If the identity of the survivor matters — it is the record you email, invoice or act on — the fix is to make the ordering specific enough that no two rows of a group are equal under it. Then the disposition stops mattering, because there are no ties left. ## Choosing the policy The question to answer before writing anything is what the downstream consumer needs: - **A fixed-size result** — a report with exactly three rows per customer, a layout with three slots. Distinct consecutive numbers, and an ordering specific enough to make the choice honest. - **Fair treatment of equals** — prizes, shortlists, anything where excluding one of two identical rows is indefensible. A shared-number form, and a downstream consumer that tolerates a variable row count. - **The top few distinct values** — banding, tiering, *show me the three highest amounts and everyone who reached them*. The no-gap shared form. ## Where designs differ Tools do not agree here, so nothing about the default is portable. Some numbering surfaces offer every disposition through an option; some offer only distinct consecutive numbers and expect a shared-number form to be built from a separate comparison. Defaults differ between tools that both offer the full set. The habit that travels is: **state the disposition at the call, and assert the result's row count afterwards** — a group that returned four rows from a cut at three is not a bug if you chose that, and is a silent defect if you did not. ## What the interviewer is listening for Not the names of the dispositions — the *consequence chain*: equal rows exist, the ordering cannot separate them, the disposition decides, and the decision reaches the row count of the result and the identity of the rows in it. A candidate who says *it keeps three rows* without qualification has never had a tie at the cut, or has had one and never noticed.

  • Under distinct consecutive numbering, how do you make the surviving row deterministic?
    Remove the tie rather than manage it: make the ordering specific enough that no two rows of a group are equal under it. Once the ordering separates every pair, all dispositions agree and the survivor is a property of your data instead of an accident of row arrival.
  • A cut at three returned 2,900 rows from 1,000 groups. What are the plausible causes?
    Two pull in opposite directions. Groups smaller than three contribute fewer rows and drag the total under 3,000; ties at the cut under a shared-number disposition push it over. Getting 2,900 most likely means many small groups, possibly with some tie inflation hidden inside the shortfall.
  • Why does the no-gap shared form behave badly on a column with few distinct values?
    Because the cut then selects distinct values, not rows. If a group's amounts take only four distinct values, a cut at three keeps the rows of three of them — which can be nearly the whole group. The result's size is governed by the column's distinctness, not by the cut.

Two runners dead-heat for first. You can award two golds and no silver, hand out gold then silver as if the dead heat resolved itself, or go to the photo finish and force an order. The race did not change; the medal table did.

saying these in an interview costs you the question

  • Assumes a cut at three always returns exactly three rows.
  • Treats the tie disposition as cosmetic rather than as what decides survival.
  • Believes distinct consecutive numbering picks the tied winner by a rule in the data.
  • Thinks shared numbers with and without a gap keep the same rows.
  • Expects every tool to default to the same disposition.
open as a page

Orders are grouped by customer and each row numbered inside its group by date; what does a five-order customer receive?

level: juniorimportance: should knowfreq 60%

basics

~20 s

Five numbers, one per row, running 1 to 5 and restarting at every customer. A position inside a group is a per-row value, not a single value for the group, and the chosen ordering decides which row is 1.

open as a page

A running total is carried down each group's rows under a chosen ordering — how does it differ from the group's total?

level: middleimportance: should knowfreq 57%

basics

~20 s

A running total is one value per row — that row plus every earlier row of the same group under the chosen ordering. The group's total is one value for the whole group, and it is what the group's last row already holds.

open as a page

A per-group numbering returned different rows this month with no code change — what should you check about its ordering?

level: seniorimportance: should knowfreq 50%

basics

~20 s

Check whether the numbering states its own ordering or inherits the row order it happens to find. An inherited ordering is owned by whatever step ran before it, so an unrelated upstream change silently renumbers every group.

open as a page