/* normalizeCrossTab: Converts crosstab format to normalized form. Given columns abcDE, the user puts the cursor somewhere in column D. The result is a new sheet, NormalizedResult, like this: a b c Field Value a1 b1 c1 D D1 a1 b1 c1 E E1 a2 b2 c2 D D2 a2 b2 c2 E E2 ... Author: Steve Bennett stevage@gmail.com @stevage1 Licence: Public Domain */ function start() { var html = HtmlService.createHtmlOutput( '' + '' + '' + '' + '

Convert cross-tab

'+ '

This macro converts cross-tab data which has multiple dependent variables (eg, observations, sales figures) per row into a normalized format with one dependent variable per row.

' + '

The name of each dependent variable becomes the value of a new column called Field and its value goes in a column called Value.

' + '
  1. Move all independent variable columns to the left
  2. ' + '
  3. Place the cursor in the first dependent variable column
'+ '

' + '

' + '

' + '

More information

') .setSandboxMode(HtmlService.SandboxMode.IFRAME) .setTitle('Normalize cross-tab') .setWidth(300); SpreadsheetApp.getUi() // Or DocumentApp or FormApp. .showSidebar(html); } function onOpen() { var ss = SpreadsheetApp.getActive(); var items = [ {name: 'Normalize Crosstab', functionName: 'start'}, ]; ss.addMenu('Normalize', items); } function normalizeCrosstab(really) { if (!really) { return start(); } var sheet = SpreadsheetApp.getActiveSheet(); var rows = sheet.getDataRange(); var numRows = rows.getNumRows(); var values = rows.getValues(); var firstDataCol = SpreadsheetApp.getActiveRange().getColumn(); var dataCols = values[0].slice(firstDataCol-1); var resultssheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("NormalizedResult"); if (resultssheet != null) { SpreadsheetApp.getActive().deleteSheet(resultssheet); } var header = values[0].slice(0, firstDataCol - 1); var newRows = []; header.push("Field"); header.push("Value"); newRows.push(header); for (var i = 1; i <= numRows - 1; i++) { var row = values[i]; for (var datacol = 0; datacol < dataCols.length; datacol ++) { newRow = row.slice(0, firstDataCol - 1); // copy repeating portion of each row newRow.push(values[0][firstDataCol - 1 + datacol]); // field name newRow.push(values[i][firstDataCol - 1 + datacol]); // field value newRows.push(newRow); } } var newSheet = SpreadsheetApp.getActiveSpreadsheet().insertSheet("NormalizedResult"); var r = newSheet.getRange(1,1,newRows.length, header.length); r.setValues(newRows); }; function getDataColumns() { var sheet = SpreadsheetApp.getActiveSheet(); var rows = sheet.getDataRange(); var values = rows.getValues(); var firstDataCol = SpreadsheetApp.getActiveRange().getColumn(); var dataCols = values[0].slice(firstDataCol-1); return dataCols; }