skip to content

Getting Data In and Out

Every dataset arrives through a reader that guessed at it and leaves through a writer that dropped something. A large share of wrong answers are already baked in before the first analysis step.

on this pageshow

explore

questions

22

A column of zero-padded account codes comes back as numbers with the zeros gone. What did the reader do, and what would have prevented it?

level: juniorimportance: must knowfreq 72%

answer

  1. digits are not a type
  2. notation is not value
  3. lost at parse, not at print
  4. re-padding needs a fixed width
  5. would you ever add two of them

basics

~20 s

Every field in that column looked like digits, so the reader chose a numeric representation and parsed the characters into values. Leading zeros carry no numeric value, so they were discarded during the read. Stating the column as text prevents it.

solid answer

~50 s

The reader inspected the column, saw nothing but digits, and picked a numeric representation for it. Parsing then converts the characters into a number, and a number has no memory of how it was written: leading zeros, any plus sign, and any separators inside the field are simply not part of the value. The loss happens at the read, not at display time, so no later formatting step can reliably undo it — re-padding only works when every code is the same known width, and identifier schemes frequently are not. The fix is to tell the reader that column is text when you call it, or to give it a per-column conversion hook, so the characters are carried through as characters. The wider lesson: an identifier is not a quantity, and any column you will never do arithmetic on is a column the reader should not be allowed to guess about.

go deeper

for a junior

Recall that a column of digits is not automatically numeric, and that leading zeros vanish when characters are parsed into a number. Know that you can state the column as text at the read.

for a middle

Explain that the loss is at parse time and therefore usually unrecoverable, and be able to say when re-padding works and when it does not. Mention the related loss for identifiers longer than the numeric width holds exactly.

for a senior

Demonstrate that you plan the identifier columns before the first read of a new feed, and can say what you would check to prove none of them was silently converted.

for a principal

The angle is where this belongs: if identifiers arrive in a shape with no types in it, every consumer repeats the same declaration and one of them eventually forgets. That is an argument about what the producer emits, not about readers.

## Why this happens at all A file that stores every value as characters hands the reader a column of fields like `00471`, `00038`, `01900`. Nothing in the file says these are codes. The reader inspects some of them, sees digits and only digits, and concludes the column is numeric — which is the most useful conclusion it could draw if the column really were quantities. Having chosen, it parses. **Parsing is the point of loss.** Converting `00471` into a number produces the value four hundred and seventy-one; the two leading zeros are notation, not value, and a number does not carry its notation around. When you later look at the column you see `471`, and the characters that made it an identifier are gone from the table entirely. ## Why you cannot repair it afterwards The instinct is to format the column back: pad every value out to a fixed width with zeros. That works only when you know the width and the width is the same for every code. - If the scheme is fixed-width, re-padding recovers the original strings, and you got lucky. - If code lengths vary — some five characters, some seven — the number no longer tells you how many zeros to restore, and there is no way back from the table alone. - If a code could contain a separator, a plus sign or spacing that was significant, the same argument applies with no fixed-width escape hatch. Two neighbouring losses come from the same cause. An identifier long enough to exceed the exact range of the chosen numeric width comes back subtly altered rather than truncated at the front, which is worse because it looks fine. And an identifier that happens to contain a decimal point or an exponent marker can be read as a fractional quantity, which reprints in a form the producing system will not recognise. ## The general rule underneath **Digits are not a type.** A postal code, an account number, a product code, a national identifier, a phone number and a year-plus-sequence reference are all written with digits and none of them is a quantity. The test is not what the characters look like; it is whether you would ever add two of them together. If you would not, the column is text and should be read as text. This is the clearest case of a general property of an inferred type: **the guess is optimised for the common case and has no idea what your data means.** The reader is not wrong about the characters. It is wrong about the domain, and it has no access to the domain. ## The two fixes, and how they differ 1. **State the type at the read.** Tell the reader that column is text. It then carries the characters through untouched. This is one statement, costs nothing at read time, and is the answer in almost every case. 2. **Hand the reader a per-column conversion hook.** Some readers let you supply your own conversion for a named column. Say the hook's shape before you say its cost: if the reader hands it one field at a time, you pay a host-language call per field and the conversion, not the parse, becomes the expensive part of the read; if the same surface hands it the whole column at once, or accepts a stated type instead of a function, it runs at the reader's own speed. Use the hook when the column genuinely needs transforming, not merely to keep it as text. ## What good looks like in practice - Identify the identifier columns before the first read, not after the first wrong join. They are usually obvious from the column names. - State their types at the read, alongside whatever else you state. - Notice that this is cheap insurance in both directions: if a column you declared as text later needs to be numeric, you convert it deliberately and see the failures; if a column you let the reader guess about was destroyed, you may not find out for months. And be aware of the variation across designs, because the same file does not behave the same everywhere. Where the reader is built to guess, this bites by default. Where the reader leaves every column as text unless told otherwise, it never bites and the opposite complaint is heard — that you must state the numeric columns yourself. Where the file declares its own types, whatever the producer wrote is what you get, and the question moves to the producer. Knowing which of the three you are dealing with is the actual skill.

  • Why is an identifier longer than the numeric width worse than one with leading zeros?
    Leading zeros are visibly missing, so somebody notices. An identifier beyond the range the representation holds exactly comes back as a nearby value of the same length — it still looks like an identifier, it joins against nothing, and every check that only looks at the shape of the column passes.
  • Is converting the column back to text after the read equivalent to stating the type at the read?
    No. Converting afterwards operates on the parsed values, so it reproduces whatever survived the parse, not the original characters. Only stating the type at the read keeps the reader from parsing them in the first place.

Typing a phone number into a calculator. The calculator is not broken and it did not lie to you; it simply treats what you typed as a quantity, and a quantity has no leading zeros, no spacing and no country prefix. What comes back is a number that is no longer a phone number.

saying these in an interview costs you the question

  • Says the zeros are only hidden and can always be formatted back
  • Treats any column of digits as a numeric column
  • Blames the file or the producer rather than the read
  • Thinks the loss happens when the value is displayed
  • Suggests converting the column back to text after the read as a complete fix
  • Assumes a long identifier survives a numeric representation exactly
open as a page

A plain text file carries no type information. How does a reader decide each column's type, and why might it decide differently next month?

level: juniorimportance: must knowfreq 78%

basics

~20 s

A reader over a file with no declared types guesses each column's type from the rows it inspects, then holds every value in that column to that one representation. Different rows next month can produce a different guess.

open as a page

A file larger than memory is read in pieces on one machine: what is one piece, and where may the cuts fall?

level: juniorimportance: must knowfreq 64%

basics

~20 s

One piece is a batch of whole records handed back per turn of the loop, not an arbitrary byte range: cuts must fall on record boundaries, and the line naming the columns belongs to the first turn only.

open as a page

The same dataset is stored as delimited text and as a self-describing binary columnar file: what does each read have to decide?

level: juniorimportance: must knowfreq 62%

basics

~20 s

A self-describing binary columnar file carries its own type declaration, so the read applies it. Delimited text carries characters only, so something outside the file decides what each field means — on every read, and possibly differently the next time.

open as a page

Right after a reader turns a delimited text file into a table, what arithmetic tells you it dropped records?

level: juniorimportance: must knowfreq 66%

basics

~20 s

Compare rows in the table against a count you knew independently: lines in the file minus the line that names the columns, or the count the producer stated. Equal is reassurance; unequal is the alarm the read never raised.

open as a page

A table with declared column types is written out as one-record-per-line text and read back — what is no longer guaranteed?

level: juniorimportance: must knowfreq 70%

basics

~20 s

The types are not guaranteed. Text stores characters only, so the reader must decide afresh what each field is. A file that carries its own type declarations restores them; flat text has nowhere to put them.

open as a page

In a piece-by-piece read, one piece types a column as a number and a later piece as text: why, and what prevents it?

level: middleimportance: must knowfreq 57%

basics

~20 s

A reader that guesses decides per turn, and each turn sees only its own rows, so a late awkward value or a blank field flips the decision. Hand every turn the same type declaration up front.

open as a page

A line in an otherwise healthy delimited file does not fit the table's shape: what can the reader do with it?

level: middleimportance: must knowfreq 58%

basics

~20 s

Three dispositions: stop the read, drop the record — in silence or into a warning nobody reads — or hand it back damaged with the missing fields padded. Only the third keeps the row count, which is why it hides best.

open as a page

Which literal strings in a file does a reader turn into absent markers, and when does that default destroy real values?

level: middleimportance: should knowfreq 58%

basics

~20 s

Readers ship a built-in list of spellings — an empty field, a dash, a question mark, short abbreviations for unavailable — and map any field matching one to the absent-value marker. A real value spelled the same way is destroyed, silently.

open as a page

Before a reader fixes a column's type, what might it have inspected, and how does each choice change the answer?

level: middleimportance: should knowfreq 56%

basics

~20 s

Readers differ: some fix a type from a bounded prefix of the file, some scan the whole column first, some decide afresh for every batch of rows, and some refuse to guess at all. Which rule applies decides whether a late contradicting value is ever seen.

open as a page

How do you choose how many rows the reader hands back per turn, and what does too small or too large cost?

level: middleimportance: should knowfreq 42%

basics

~20 s

Balance a fixed cost paid once per turn, which is divided over the rows in the batch, against a peak that scales with the batch. Too small is slow, too large stops bounding anything; measure, do not quote a number.

open as a page

A read asks for 3 of a file's 200 columns: what does that avoid on a columnar layout, and what on delimited text?

level: middleimportance: should knowfreq 58%

basics

~20 s

On a declared columnar layout the unread columns are never read from disk at all. On delimited text every byte of every line still crosses the parser to find the separators; only converting and keeping the unwanted columns is avoided.

open as a page

A column held as integer codes with a declared list of permitted values is written to text — what comes back?

level: middleimportance: should knowfreq 40%

basics

~20 s

The values come back; the declaration does not. Text writes out the values the codes stood for, so the reader sees ordinary characters, and any list rebuilt afterwards holds only what this file happened to contain.

open as a page

After two write-and-read-back cycles through text, a table carries two extra leading columns of numbers — why?

level: middleimportance: should knowfreq 55%

basics

~10 s

Each trip wrote the table's row labels out as an ordinary leading column, and each read brought them back as plain data. Two trips, two columns. Tables with no row-identity concept never show it.

open as a page

A nightly read warns on 300 fields that contradict the type it chose, then hands back a table anyway. What are the reader's options, and which do you want?

level: seniorimportance: should knowfreq 50%

basics

~20 s

A reader meeting a value that contradicts a column's type can reject the read, coerce the value into the type, or widen the whole column to text; some also drop the record. In an unattended nightly job you want rejection, because a warning is a non-signal.

open as a page

A pass in pieces over a 180-column file needs four of them: what does naming those four at the read change, and does the file's shape matter?

level: seniorimportance: should knowfreq 49%

basics

~20 s

Naming them at the read avoids converting and keeping 176 columns on every turn. Whether it also avoids reading their bytes depends on the shape: a columnar layout never fetches them, while delimited text still reads and splits every line.

open as a page

A read in pieces still exhausted memory: every piece was appended to a list and joined at the end. Where was the peak?

level: seniorimportance: should knowfreq 53%

basics

~10 s

At the combination step. Every piece is still referenced by the list while the joined result is allocated alongside it, so the peak is at least the finished table plus all the pieces.

open as a page

A process must keep adding records to a dataset on disk: what does appending cost on each of the two file shapes, and what accumulates?

level: seniorimportance: should knowfreq 46%

basics

~20 s

Delimited text takes new records by concatenation, so appending is nearly free. A finalised typed file generally cannot be extended byte by byte, so each addition becomes another file — and every later read then pays a fixed cost per file.

open as a page

A table read from a delimited file holds rows whose values sit one column right, and fewer rows than the file has lines. What produced each symptom?

level: seniorimportance: should knowfreq 50%

basics

~20 s

Two different faults. A separator inside a field's own text pushes every later value one position right within that line. A line break inside a value makes one record out of two lines, so rows fall below the line count.

open as a page

A read of a file whose tail was never written finishes without complaint — what did the reader hand back?

level: seniorimportance: should knowfreq 42%

basics

~20 s

A shorter table, with nothing to say so. Delimited text carries no record count, so a file cut off mid-write reads like a shorter complete file; the last partial line either parses wrongly or meets the malformed-line disposition.

open as a page

A nightly export writes a table to text and a reload comparison fails on a few decimal values — what happened, and what test catches this class?

level: seniorimportance: should knowfreq 48%

basics

~20 s

The file holds what the writer printed, not the value, so the reload re-parses a printed decimal. Whether that is lossless depends on how many digits the writer prints. Write, read straight back, and compare.

open as a page

A team choosing one file shape for the datasets it hands between its own steps keeps arguing file size: what should decide it instead?

level: principalimportance: should knowfreq 38%

basics

~20 s

File size is the difference that decides least. Decide on who must be able to open the file without your code, how much of it a typical read touches, whether types must be guaranteed rather than re-established, and how the dataset is produced.

open as a page