Unfolding Column Groups - BareFrame.unfoldColumns¶
BareFrame.unfoldColumns expands repeated column groups into separate rows.
Use it when a sheet stores multiple items per row as side-by-side column groups,
and you need each item as its own row.
const unfolded = df.unfoldColumns({
fixedHeaders: ["timestamp", "email"],
groups: [
["person1_name", "person1_age"],
["person2_name", "person2_age"],
],
groupHeaders: ["name", "age"],
});
Without gaslamp¶
Google Sheets has no built-in operation to unfold column groups into rows. You must write a nested loop manually, keeping track of which columns belong to each group:
const values = sheet.getDataRange().getValues();
const headers = values[0];
// headers: ["timestamp", "email", "person1_name", "person1_age", "person2_name", "person2_age"]
const rows = values.slice(1);
const result = [];
for (const row of rows) {
// Group 1: person1_name(2), person1_age(3)
result.push([row[0], row[1], row[2], row[3]]);
// Group 2: person2_name(4), person2_age(5)
result.push([row[0], row[1], row[4], row[5]]);
}
// result:
// ["2024-03-25", "a@example.com", "Alice", 30]
// ["2024-03-25", "a@example.com", "Bob", 25]
If the sheet layout changes (columns added, reordered, or groups extended), every index must be updated manually.
With gaslamp¶
unfoldColumns expresses the same transformation with column names and group declarations.
The sheet layout can change freely as long as column names stay the same.
const df = gaslamp.BareFrame.fromSheet(sheet);
const unfolded = df.unfoldColumns({
fixedHeaders: ["timestamp", "email"],
groups: [
["person1_name", "person1_age"],
["person2_name", "person2_age"],
],
groupHeaders: ["name", "age"],
});
console.log(unfolded.display());
// | timestamp | email | name | age |
// | ---------- | ------------- | ----- | --- |
// | 2024-03-25 | a@example.com | Alice | 30 |
// | 2024-03-25 | a@example.com | Bob | 25 |
Options¶
| Option | Type | Description |
|---|---|---|
fixedHeaders |
string[] |
Columns that are copied unchanged to every output row |
groups |
string[][] |
Column groups to expand — one group becomes one output row |
groupHeaders |
string[] |
New column names for the expanded values |
strict |
boolean |
When true, throws on missing columns or size mismatches. Default: false |
groups and groupHeaders must have the same length.
Each inner array in groups must also have the same length as groupHeaders.
Strict mode¶
By default, missing columns in a group are filled with null.
Pass strict: true to throw an error instead:
const unfolded = df.unfoldColumns({
fixedHeaders: ["timestamp"],
groups: [["missing_col"]],
groupHeaders: ["name"],
strict: true,
});
// Error: BareFrame.unfoldColumns: column "missing_col" in groups[0] does not exist
Practical Workflow¶
A survey response sheet stores answers from up to 3 respondents per row. Unfold each response into its own row, then write to a normalized output sheet.
function workflow_unfoldSurvey() {
const book = SpreadsheetApp.getActiveSpreadsheet();
const inputSheet = book.getSheetByName("Survey");
const outputSheet = book.getSheetByName("Responses")
?? book.insertSheet("Responses");
const df = gaslamp.BareFrame.fromSheet(inputSheet);
const responses = df.unfoldColumns({
fixedHeaders: ["submitted_at", "team"],
groups: [
["resp1_name", "resp1_score"],
["resp2_name", "resp2_score"],
["resp3_name", "resp3_score"],
],
groupHeaders: ["name", "score"],
});
responses.toSheet(outputSheet);
console.log(`Unfolded ${df.length} rows → ${responses.length} rows.`);
}
Next Steps¶
- DataFrame and Google Sheets — full read/write reference for
BareFrame - API Reference — complete method list for
BareFrame