如何在 google 应用程序脚本中 'melt' 宽 table/array?
How to 'melt' a wide table/array in google app script?
我在 Google 工作表中有一个 array/table,数据格式如下:
Catergory1
A
A
A
A
A
B
B
B
B
B
C
C
C
C
C
Catergory2
Q1
Q2
Q3
Q4
Q5
Q1
Q2
Q3
Q4
Q5
Q1
Q2
Q3
Q4
Q5
Propotions
34%
66%
9%
49%
31%
36%
69%
1%
10%
20%
98%
38%
21%
57%
76%
我想使用 Google App Script 将此数组转换为以下格式:
Catergory1
Q1
Q2
Q3
Q4
Q5
A
34%
66%
9%
49%
31%
B
36%
69%
1%
10%
20%
C
98%
38%
21%
57%
76%
提前致谢。
应用脚本
试试这个
function myFunction(){
var ss = SpreadsheetApp.getActiveSpreadsheet()
var sh = ss.getActiveSheet()
var values = sh.getRange(1,2,3,sh.getLastColumn()-1).getValues()
var rows = Array.from(new Set(values[0])).sort();
var cols = Array.from(new Set(values[1])).sort();
var result = Array.from({ length: rows.length }, () => Array.from({ length: cols.length }, () => ''));
for (var i=0;i<sh.getLastColumn()-1;i++){
result[rows.indexOf(values[0][i])][cols.indexOf(values[1][i])] = values[2][i]
}
sh.getRange(6,1,rows.length,1).setValues(transpose([rows]))
sh.getRange(5,2,1,cols.length).setValues([cols])
sh.getRange(6,2,rows.length,cols.length).setValues(result)
}
function transpose(a){
return Object.keys(a[0]).map(function (c) { return a.map(function (r) { return r[c]; }); });
}
公式
=query(TRANSPOSE(B1:3),"select Col1, sum(Col3) where Col1 is not null group by Col1 pivot Col2")
这是我的变体:
function myFunction() {
var sheet = SpreadsheetApp.getActiveSheet();
// get the data (without first column)
var data = sheet.getDataRange().getDisplayValues().map(x => x.slice(1));
// get rows and columns names
var rows = Array.from(new Set(data[0])); // A, B, C...
var cols = Array.from(new Set(data[1])); // Q1, Q2, Q3...
// create the empty table
var table = Array(rows.length).fill('')
.map(x => x = Array(cols.length).fill(''));
// fill the table with values from third row of data ('Proportions')
for (let i in data[0]) {
let row = rows.indexOf(data[0][i]);
let col = cols.indexOf(data[1][i]);
table[row][col] = data[2][i];
}
// add the header and first column (A,B,C...) to the table
var header = ['Category', ...cols];
var body = table.map((x,i) => [rows[i], ...x]);
table = [header, ...body];
// put the table on the sheet
sheet.clear().getRange(1,1,table.length,table[0].length).setValues(table);
// set font of the header to 'Bold'
sheet.getRange(1,1,1,sheet.getLastColumn()).setFontWeight('Bold');
}
它应该适用于任意数量的类别和字母。而且它甚至不需要对列进行排序,它们可以像:Q1、Q3、Q1、Q2...等等
如果您的数据总是经过排序,则脚本可以更简单一些并且可能更高效:
function myFunction2() {
var sheet = SpreadsheetApp.getActiveSheet();
var data = sheet.getDataRange().getDisplayValues();
var letters = Array.from(new Set(data[0].slice(1))); // A,B,C
var categories = Array.from(new Set(data[1].slice(1))); // Q1,Q2,Q3,Q4,Q5
var proportions = data[2].slice(1); // %,%,%...
// make a table from the proportions
var table = [];
var rows = letters.length
while (rows--) {
var row = [];
var cols = categories.length;
while (cols--) row.push(proportions.shift());
table.push(row);
}
// add a header and first column to the table
var header = ['Categories', ...categories];
var body = table.map(x => [letters.shift(), ...x]);
table = [header, ...body];
// put the table on the sheet
sheet.clear().getRange(1,1,table.length,table[0].length).setValues(table);
}
我在 Google 工作表中有一个 array/table,数据格式如下:
Catergory1 | A | A | A | A | A | B | B | B | B | B | C | C | C | C | C |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Catergory2 | Q1 | Q2 | Q3 | Q4 | Q5 | Q1 | Q2 | Q3 | Q4 | Q5 | Q1 | Q2 | Q3 | Q4 | Q5 |
Propotions | 34% | 66% | 9% | 49% | 31% | 36% | 69% | 1% | 10% | 20% | 98% | 38% | 21% | 57% | 76% |
我想使用 Google App Script 将此数组转换为以下格式:
Catergory1 | Q1 | Q2 | Q3 | Q4 | Q5 |
---|---|---|---|---|---|
A | 34% | 66% | 9% | 49% | 31% |
B | 36% | 69% | 1% | 10% | 20% |
C | 98% | 38% | 21% | 57% | 76% |
提前致谢。
应用脚本
试试这个
function myFunction(){
var ss = SpreadsheetApp.getActiveSpreadsheet()
var sh = ss.getActiveSheet()
var values = sh.getRange(1,2,3,sh.getLastColumn()-1).getValues()
var rows = Array.from(new Set(values[0])).sort();
var cols = Array.from(new Set(values[1])).sort();
var result = Array.from({ length: rows.length }, () => Array.from({ length: cols.length }, () => ''));
for (var i=0;i<sh.getLastColumn()-1;i++){
result[rows.indexOf(values[0][i])][cols.indexOf(values[1][i])] = values[2][i]
}
sh.getRange(6,1,rows.length,1).setValues(transpose([rows]))
sh.getRange(5,2,1,cols.length).setValues([cols])
sh.getRange(6,2,rows.length,cols.length).setValues(result)
}
function transpose(a){
return Object.keys(a[0]).map(function (c) { return a.map(function (r) { return r[c]; }); });
}
公式
=query(TRANSPOSE(B1:3),"select Col1, sum(Col3) where Col1 is not null group by Col1 pivot Col2")
这是我的变体:
function myFunction() {
var sheet = SpreadsheetApp.getActiveSheet();
// get the data (without first column)
var data = sheet.getDataRange().getDisplayValues().map(x => x.slice(1));
// get rows and columns names
var rows = Array.from(new Set(data[0])); // A, B, C...
var cols = Array.from(new Set(data[1])); // Q1, Q2, Q3...
// create the empty table
var table = Array(rows.length).fill('')
.map(x => x = Array(cols.length).fill(''));
// fill the table with values from third row of data ('Proportions')
for (let i in data[0]) {
let row = rows.indexOf(data[0][i]);
let col = cols.indexOf(data[1][i]);
table[row][col] = data[2][i];
}
// add the header and first column (A,B,C...) to the table
var header = ['Category', ...cols];
var body = table.map((x,i) => [rows[i], ...x]);
table = [header, ...body];
// put the table on the sheet
sheet.clear().getRange(1,1,table.length,table[0].length).setValues(table);
// set font of the header to 'Bold'
sheet.getRange(1,1,1,sheet.getLastColumn()).setFontWeight('Bold');
}
它应该适用于任意数量的类别和字母。而且它甚至不需要对列进行排序,它们可以像:Q1、Q3、Q1、Q2...等等
如果您的数据总是经过排序,则脚本可以更简单一些并且可能更高效:
function myFunction2() {
var sheet = SpreadsheetApp.getActiveSheet();
var data = sheet.getDataRange().getDisplayValues();
var letters = Array.from(new Set(data[0].slice(1))); // A,B,C
var categories = Array.from(new Set(data[1].slice(1))); // Q1,Q2,Q3,Q4,Q5
var proportions = data[2].slice(1); // %,%,%...
// make a table from the proportions
var table = [];
var rows = letters.length
while (rows--) {
var row = [];
var cols = categories.length;
while (cols--) row.push(proportions.shift());
table.push(row);
}
// add a header and first column to the table
var header = ['Categories', ...categories];
var body = table.map(x => [letters.shift(), ...x]);
table = [header, ...body];
// put the table on the sheet
sheet.clear().getRange(1,1,table.length,table[0].length).setValues(table);
}