在 google 工作表中将宽转换为长时跳过空白值
Skip blank values when converting wide to long in google sheets
我正在使用这个出色的脚本将 google 页 中的宽 table 转换为长 table。
代码:
/**
* Unpivot a pivot table of any size.
*
* @param {A1:D30} data The pivot table.
* @param {1} fixColumns Number of columns, after which pivoted values begin. Default 1.
* @param {1} fixRows Number of rows (1 or 2), after which pivoted values begin. Default 1.
* @param {"city"} titlePivot The title of horizontal pivot values. Default "column".
* @param {"distance"[,...]} titleValue The title of pivot table values. Default "value".
* @return The unpivoted table
* @customfunction
*/
function unpivot(data,fixColumns,fixRows,titlePivot,titleValue) {
var fixColumns = fixColumns || 1; // how many columns are fixed
var fixRows = fixRows || 1; // how many rows are fixed
var titlePivot = titlePivot || 'column';
var titleValue = titleValue || 'value';
var ret=[],i,j,row,uniqueCols=1;
// we handle only 2 dimension arrays
if (!Array.isArray(data) || data.length < fixRows || !Array.isArray(data[0]) || data[0].length < fixColumns)
throw new Error('no data');
// we handle max 2 fixed rows
if (fixRows > 2)
throw new Error('max 2 fixed rows are allowed');
// fill empty cells in the first row with value set last in previous columns (for 2 fixed rows)
var tmp = '';
for (j=0;j<data[0].length;j++)
if (data[0][j] != '')
tmp = data[0][j];
else
data[0][j] = tmp;
// for 2 fixed rows calculate unique column number
if (fixRows == 2)
{
uniqueCols = 0;
tmp = {};
for (j=fixColumns;j<data[1].length;j++)
if (typeof tmp[ data[1][j] ] == 'undefined')
{
tmp[ data[1][j] ] = 1;
uniqueCols++;
}
}
// return first row: fix column titles + pivoted values column title + values column title(s)
row = [];
for (j=0;j<fixColumns;j++) row.push(fixRows == 2 ? data[0][j]||data[1][j] : data[0][j]); // for 2 fixed rows we try to find the title in row 1 and row 2
for (j=3;j<arguments.length;j++) row.push(arguments[j]);
ret.push(row);
// processing rows (skipping the fixed columns, then dedicating a new row for each pivoted value)
for (i=fixRows; i<data.length && data[i].length > 0; i++)
{
// skip totally empty or only whitespace containing rows
if (data[i].join('').replace(/\s+/g,'').length == 0 ) continue;
// unpivot the row
row = [];
for (j=0;j<fixColumns && j<data[i].length;j++)
row.push(data[i][j]);
for (j=fixColumns;j<data[i].length;j+=uniqueCols)
ret.push(
row.concat([data[0][j]]) // the first row title value
.concat(data[i].slice(j,j+uniqueCols)) // pivoted values
);
}
return ret;
}
但是,我有很多行和列,结果 table 有太多行无法输出。我的数据中有很多空白。我想跳过写入具有空白值的行,如下所示:
宽幅面:
Region Activity1 Activity2 Activity3
A 1 2
B 1
C 1
所需的长格式:
Region ActivityName Frequency
A Activity1 1
A Activity3 2
B Activity2 1
C Activity1 1
我目前正在使用链接答案中的代码。我收到的错误是:"Error Result too large." 如果我可以跳过空白值,我的结果肯定不会太大。
重新创建脚本似乎比调试脚本更容易。
此脚本假定数据从单元格 A1 开始。
关键要素
- 创建两个临时数组:一个保存行值,另一个保存行数组的渐进式编译
- 遍历行和列
- 每次列值不为空时向数组添加一个值集
- 完成后,更新新的数组值
- 不要忘记删除 "new" 数据
列之外的 "old" 数据列
function so6049421501() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheetname = "Sheet1";
var sheet = ss.getSheetByName(sheetname);
// get data
var range = sheet.getDataRange();
// Logger.log("DEBUG: source range = "+range.getA1Notation())
var data = range.getValues();
// get number ofrows in the source data
var fixRows = range.getNumRows()-1;
var fixColumns = range.getNumColumns()-1;
// Logger.log("DEBUG: rows = "+fixRows+", columns = +fixColumns");
// create a new array to hold values
var newarray = [];
// set the number of columns in the new array
var numCols = 3;
// add header row
newarray.push(["Region","ActivityName","Frequency"]);
for (var r = 0;r<fixRows;r++){
for (var c=0;c<fixColumns;c++){
// create a new array to hold the values for this row
var rowarray = [];
// if column isn't blank
if (data[+r+1][+c+1] !==""){
// column isn't blank
// push the region
// Logger.log("DEBUG: region = "+data[r+1][0]);
rowarray.push(data[r+1][0])
// push the activity
// Logger.log("DEBUG: activity = "+data[0][+c+1]);
rowarray.push(data[0][+c+1])
// push the frequency
DEBUG: Logger.log("Frequency = "+data[+r+1][+c+1])
rowarray.push(data[+r+1][+c+1]);
//Logger.log(rowarray)
newarray.push(rowarray);
}
}
}
// Logger.log(newarray);
//Logger.log("DEBUG: new array len = "+newarray.length);
// Logger.log("DEBUG: target range = "+sheet.getRange(1, 1, newarray.length, numCols).getA1Notation());
// Update the new array
sheet.getRange(1, 1, newarray.length, numCols).setValues(newarray);
// delete the data in the unused columns
sheet.getRange(1,4,+fixRows+1,+fixColumns+1-numCols).clear()
return;
}
我正在使用这个出色的脚本将 google 页 中的宽 table 转换为长 table。
代码:
/**
* Unpivot a pivot table of any size.
*
* @param {A1:D30} data The pivot table.
* @param {1} fixColumns Number of columns, after which pivoted values begin. Default 1.
* @param {1} fixRows Number of rows (1 or 2), after which pivoted values begin. Default 1.
* @param {"city"} titlePivot The title of horizontal pivot values. Default "column".
* @param {"distance"[,...]} titleValue The title of pivot table values. Default "value".
* @return The unpivoted table
* @customfunction
*/
function unpivot(data,fixColumns,fixRows,titlePivot,titleValue) {
var fixColumns = fixColumns || 1; // how many columns are fixed
var fixRows = fixRows || 1; // how many rows are fixed
var titlePivot = titlePivot || 'column';
var titleValue = titleValue || 'value';
var ret=[],i,j,row,uniqueCols=1;
// we handle only 2 dimension arrays
if (!Array.isArray(data) || data.length < fixRows || !Array.isArray(data[0]) || data[0].length < fixColumns)
throw new Error('no data');
// we handle max 2 fixed rows
if (fixRows > 2)
throw new Error('max 2 fixed rows are allowed');
// fill empty cells in the first row with value set last in previous columns (for 2 fixed rows)
var tmp = '';
for (j=0;j<data[0].length;j++)
if (data[0][j] != '')
tmp = data[0][j];
else
data[0][j] = tmp;
// for 2 fixed rows calculate unique column number
if (fixRows == 2)
{
uniqueCols = 0;
tmp = {};
for (j=fixColumns;j<data[1].length;j++)
if (typeof tmp[ data[1][j] ] == 'undefined')
{
tmp[ data[1][j] ] = 1;
uniqueCols++;
}
}
// return first row: fix column titles + pivoted values column title + values column title(s)
row = [];
for (j=0;j<fixColumns;j++) row.push(fixRows == 2 ? data[0][j]||data[1][j] : data[0][j]); // for 2 fixed rows we try to find the title in row 1 and row 2
for (j=3;j<arguments.length;j++) row.push(arguments[j]);
ret.push(row);
// processing rows (skipping the fixed columns, then dedicating a new row for each pivoted value)
for (i=fixRows; i<data.length && data[i].length > 0; i++)
{
// skip totally empty or only whitespace containing rows
if (data[i].join('').replace(/\s+/g,'').length == 0 ) continue;
// unpivot the row
row = [];
for (j=0;j<fixColumns && j<data[i].length;j++)
row.push(data[i][j]);
for (j=fixColumns;j<data[i].length;j+=uniqueCols)
ret.push(
row.concat([data[0][j]]) // the first row title value
.concat(data[i].slice(j,j+uniqueCols)) // pivoted values
);
}
return ret;
}
但是,我有很多行和列,结果 table 有太多行无法输出。我的数据中有很多空白。我想跳过写入具有空白值的行,如下所示:
宽幅面:
Region Activity1 Activity2 Activity3
A 1 2
B 1
C 1
所需的长格式:
Region ActivityName Frequency
A Activity1 1
A Activity3 2
B Activity2 1
C Activity1 1
我目前正在使用链接答案中的代码。我收到的错误是:"Error Result too large." 如果我可以跳过空白值,我的结果肯定不会太大。
重新创建脚本似乎比调试脚本更容易。 此脚本假定数据从单元格 A1 开始。
关键要素
- 创建两个临时数组:一个保存行值,另一个保存行数组的渐进式编译
- 遍历行和列
- 每次列值不为空时向数组添加一个值集
- 完成后,更新新的数组值
- 不要忘记删除 "new" 数据 列之外的 "old" 数据列
function so6049421501() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheetname = "Sheet1";
var sheet = ss.getSheetByName(sheetname);
// get data
var range = sheet.getDataRange();
// Logger.log("DEBUG: source range = "+range.getA1Notation())
var data = range.getValues();
// get number ofrows in the source data
var fixRows = range.getNumRows()-1;
var fixColumns = range.getNumColumns()-1;
// Logger.log("DEBUG: rows = "+fixRows+", columns = +fixColumns");
// create a new array to hold values
var newarray = [];
// set the number of columns in the new array
var numCols = 3;
// add header row
newarray.push(["Region","ActivityName","Frequency"]);
for (var r = 0;r<fixRows;r++){
for (var c=0;c<fixColumns;c++){
// create a new array to hold the values for this row
var rowarray = [];
// if column isn't blank
if (data[+r+1][+c+1] !==""){
// column isn't blank
// push the region
// Logger.log("DEBUG: region = "+data[r+1][0]);
rowarray.push(data[r+1][0])
// push the activity
// Logger.log("DEBUG: activity = "+data[0][+c+1]);
rowarray.push(data[0][+c+1])
// push the frequency
DEBUG: Logger.log("Frequency = "+data[+r+1][+c+1])
rowarray.push(data[+r+1][+c+1]);
//Logger.log(rowarray)
newarray.push(rowarray);
}
}
}
// Logger.log(newarray);
//Logger.log("DEBUG: new array len = "+newarray.length);
// Logger.log("DEBUG: target range = "+sheet.getRange(1, 1, newarray.length, numCols).getA1Notation());
// Update the new array
sheet.getRange(1, 1, newarray.length, numCols).setValues(newarray);
// delete the data in the unused columns
sheet.getRange(1,4,+fixRows+1,+fixColumns+1-numCols).clear()
return;
}