Skip to content

Add unsparsify --from-header to fill ragged short rows from the input header - #2308

Open
Assertive-xxh wants to merge 1 commit into
johnkerl:mainfrom
Assertive-xxh:unsparsify-from-header-2286
Open

Assertive-xxh wants to merge 1 commit into
johnkerl:mainfrom
Assertive-xxh:unsparsify-from-header-2286

Conversation

@Assertive-xxh

@Assertive-xxh Assertive-xxh commented Nov 13, 2026 •

Copy link
Copy Markdown

Fixes #2286.

Since #1428 the CSV reader leaves ragged short rows short, and filling them is left to unsparsify. But unsparsify can't see the input header: without -f it only knows the keys that occur in some record, and -f a,b,c needs the names typed out. So when the first data line is the short one, the trailing columns of the header are lost:

$ printf 'a,b,c\n1,2\n4,5,6\n' | mlr --csv --ragged cat
a,b
1,2
4,5,6

This adds unsparsify --from-header, which the issue suggests as one way out:

$ printf 'a,b,c\n1,2\n4,5,6\n' | mlr --csv --ragged unsparsify --from-header
a,b,c
1,2,
4,5,6

That is the output you gave for this input in #1418. The option is opt-in: what --ragged does without it is unchanged, as decided in #1428.

How it works: the CSV, CSV-lite, TSV, PPRINT, and markdown readers put the field names of the header line into the record context (Context.HeaderFieldNames), the same way the JSON reader passes JSONHadBrackets to the JSONL writer. unsparsify --from-header fills the missing keys from there. It is streaming, and it can be combined with -f and --fill-with. The names are stored after --dedupe-field-names renaming, so they match the record keys. Input formats without a header line are left as they are.

The slice is built once per header line, not per record. mlr --icsv --ojson cat on a 2M-line, 92 MB CSV took the same time before and after (medians of 1428 ms and 1424 ms over 10 interleaved runs, Windows amd64).

I also corrected the --ragged help text and record-heterogeneity.md, which still said that short rows are filled for CSV.

Tests:

  • 13 regression cases in test/cases/verb-unsparsify-from-header/: the input from CSV to JSONL: wrong conversion? #1418 above, the four-column input from the issue, --implicit-csv-header, several files with different headers, --fill-with, -f together with --from-header, repeated header names, JSON input, and TSV, CSV-lite, PPRINT, and markdown input.
  • A unit test which checks that the header names agree with the keys PutReferenceMaybeDedupe produces.
  • go test ./pkg/... passes. golangci-lint v2.12.2 is clean with GOOS=linux.
  • mlr regtest passes on Linux (WSL, amd64): 4833 cases. On Windows under Git Bash 62 cases fail, the same number and in the same 11 case directories as on main.

Two things about the generated files. My groff is 1.23 and re-wraps all of manpage.txt, so I kept your layout and put the two changed blocks in by hand; mlr.1 is generated. And I could not regenerate three of the docs pages here (they need creach and similar), but they don't show this help text. You may want to re-run make dev.

The option name and whether it should combine with -f are yours to decide; I'm happy to change either.

Written with AI assistance (Claude); I have reviewed the change.

🤖 Generated with Claude Code

…ut header

The CSV reader has left ragged short rows short since johnkerl#1428, and unsparsify
could not see the input header, so the header's trailing columns were lost
when the first data line was short. See issue johnkerl#2286.

The CSV, CSV-lite, TSV, PPRINT, and markdown readers now put the header's
field names into the record context, and `unsparsify --from-header` fills
missing keys from there, streaming.

Also correct the `--ragged` help text and record-heterogeneity.md, which
still said that short rows are filled for CSV.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

--ragged no longer working as advertised? else add unsparsify option for whole CSV header?

1 participant