【发布时间】:2022-10-05 17:33:08
【问题描述】:
我有一个 Google Sheets 项目使用这个自定义函数 50-100 次,所以我试图让这个函数尽可能高效。该函数过滤写入 INPUT 工作表的数据(通过 Google API),然后为数据的子集绘制表格。
我在这里提供了一个工作示例电子表格:https://docs.google.com/spreadsheets/d/1KVjDl0Ix2bnlPqPEnsY4wh34MIPeayDPk3cq7DdU3g4/edit?usp=sharing
\'META\' 工作表只是通过更改单元格 A1 中的值来触发自定义函数运行(即模拟通过 Google API 填充的 INPUT 表),这是自定义函数调用的参数。
\'INPUT\' 表包含示例输入数据。该函数不使用灰色列(组名称、字段名称、类型、连接 ID、VLookup 值):
| Instance Id | Group name | Group Id | Field name | Field Id | Type | Value | File Id | Role | Concatenated Id | VLookup value |
|---|---|---|---|---|---|---|---|---|---|---|
| Instance1A | Widgets | 91c7db0a-c52a-407d-869a-af8ba8bf8ba7 | Field 1 | 09456c1a-abb4-4e81-94bd-7ce4c88afffc | CURRENCY | 100 | Pilot_File | Pilot | 09456c1a-abb4-4e81-94bd-7ce4c88afffcInstance1A | 100 |
| Instance1A | Widgets | 91c7db0a-c52a-407d-869a-af8ba8bf8ba7 | Field 2 | 474f6395-83a7-4c2b-aa5a-ceb00e200f8e | CURRENCY | 200 | Pilot_File | Pilot | 474f6395-83a7-4c2b-aa5a-ceb00e200f8eInstance1A | 200 |
| Instance1A | Widgets | 91c7db0a-c52a-407d-869a-af8ba8bf8ba7 | Field 3 | ac64e001-fe85-400a-92e4-69cebf1c260d | CURRENCY | 300 | Pilot_File | Pilot | ac64e001-fe85-400a-92e4-69cebf1c260dInstance1A | 300 |
| Instance1B | Widgets | 91c7db0a-c52a-407d-869a-af8ba8bf8ba7 | Field 1 | 09456c1a-abb4-4e81-94bd-7ce4c88afffc | CURRENCY | 110 | Pilot_File | Pilot | 09456c1a-abb4-4e81-94bd-7ce4c88afffcInstance1B | 110 |
| Instance1B | Widgets | 91c7db0a-c52a-407d-869a-af8ba8bf8ba7 | Field 2 | 474f6395-83a7-4c2b-aa5a-ceb00e200f8e | CURRENCY | 220 | Pilot_File | Pilot | 474f6395-83a7-4c2b-aa5a-ceb00e200f8eInstance1B | 220 |
| Instance1B | Widgets | 91c7db0a-c52a-407d-869a-af8ba8bf8ba7 | Field 3 | ac64e001-fe85-400a-92e4-69cebf1c260d | CURRENCY | 330 | Pilot_File | Pilot | ac64e001-fe85-400a-92e4-69cebf1c260dInstance1B | 330 |
| Instance2A | Widgets | 91c7db0a-c52a-407d-869a-af8ba8bf8ba7 | Field 1 | 09456c1a-abb4-4e81-94bd-7ce4c88afffc | CURRENCY | 1000 | Co-PIlot_File | Co-Pilot | 09456c1a-abb4-4e81-94bd-7ce4c88afffcInstance2A | 1000 |
| Instance2A | Widgets | 91c7db0a-c52a-407d-869a-af8ba8bf8ba7 | Field 2 | 474f6395-83a7-4c2b-aa5a-ceb00e200f8e | CURRENCY | 2000 | Co-PIlot_File | Co-Pilot | 474f6395-83a7-4c2b-aa5a-ceb00e200f8eInstance2A | 2000 |
| Instance2A | Widgets | 91c7db0a-c52a-407d-869a-af8ba8bf8ba7 | Field 3 | ac64e001-fe85-400a-92e4-69cebf1c260d | CURRENCY | 3000 | Co-PIlot_File | Co-Pilot | ac64e001-fe85-400a-92e4-69cebf1c260dInstance2A | 3000 |
\'TABLE_CONFIG\' 表包含结果表的配置属性。该函数未使用灰色列(描述):
| Field Id | Description | Desired table field column | Group Id |
|---|---|---|---|
| 09456c1a-abb4-4e81-94bd-7ce4c88afffc | Field 1 | 1 | 91c7db0a-c52a-407d-869a-af8ba8bf8ba7 |
| 474f6395-83a7-4c2b-aa5a-ceb00e200f8e | Field 2 | 2 | 91c7db0a-c52a-407d-869a-af8ba8bf8ba7 |
| ac64e001-fe85-400a-92e4-69cebf1c260d | Field 3 | 3 | 91c7db0a-c52a-407d-869a-af8ba8bf8ba7 |
\'RESULTS_Pilot\' 和 \'RESULTS_Co-Pilot\' 表是如何从整个电子表格的不同位置调用自定义函数的示例。标题是静态的。该函数是这样调用的:
=getTable(\"91c7db0a-c52a-407d-869a-af8ba8bf8ba7\", \"TABLE_CONFIG\", \"Pilot\", META!A1)
结果表必须始终以示例中显示的格式返回以显示:
| Instance Id | Field 1 | Field 2 | Field 3 | File Id |
|---|---|---|---|---|
| Instance1A | 100 | 200 | 300 | Pilot_File |
| Instance1B | 110 | 220 | 330 | Pilot_File |
我对编码很陌生,对 Google Apps 脚本也很陌生。自定义函数正在工作,但我希望能提供加速它的提示,或者我的代码效率低下或冗余的指针。
谢谢你。
// Filters INPUT by Group Id and Role. Called from getTable().
function filterInput(group, role) {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(\"INPUT\");
var range = sheet.getDataRange();
var values = range.getValues();
var results = [];
values.forEach(function (row) {
if (row[2] === group && row[8] === role) {
results.push(row);
}
});
return results;
}
// Builds matrix. Called from getTable().
let generateMatrix = function (m, n, value) {
let matrix = [];
for (let i = 0; i < m; i++) {
let row = [];
for (let j = 0; j < n; j++) {
row.push(value);
}
matrix.push(row);
}
return matrix;
};
// Main function called from RESULTS_Pilot and RESULTS_Co-Pilot worksheets
function getTable(groupUUID, configSheetName, role) {
// Filter INPUT tab to get only rows for group and role
values = filterInput(groupUUID, role);
// If filtered INPUT contains 0 rows, return empty string
if (values.length === 0) {
Logger.log(\"There are no matching rows in INPUT.\");
return (\"\");
}
else {
Logger.log(\"There are \" + values.length + \" filtered rows for the specified group and role.\");
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(configSheetName);
var range = sheet.getDataRange();
var configValues = range.getValues();
var configFields = 0;
var rowNum = 0;
var uniqueInstanceRows = 0; // Need to find the number of unique instance rows (i.e. unique Instance Ids) to build table
var colValues = []; // Create array with only first column values (Instance Ids) from filtered input rows
for (i = 0; i < values.length; i++) {
colValues.push(values[i][0]);
}
const unique = (value, index, self) => { return self.indexOf(value) === index; } // Get only unique Instance Ids from array
var Unique_List = colValues.filter(unique);
uniqueInstanceRows = Unique_List.length; // Will be used to build empty table using generateMatrix()
Logger.log(\"# of unique Instance Id rows: \" + uniqueInstanceRows);
configValues.forEach(function (configRow) { // Count number of config fields for the group in TABLE_CONFIG worksheet
if (configRow[3] === groupUUID && configRow[2] !== \"\") {
configFields = configFields + 1;
}
})
Logger.log(\"There are \" + configFields + \" config fields.\");
// Generate table structure
table = generateMatrix(uniqueInstanceRows + 1, configFields, \"\");
// Fill first column in results table with unique Instance Ids
for (i = 0; i < Unique_List.length; i++) {
table[i][0] = Unique_List[i];
}
// Generate a table to store Instance Id / File Id pairs
pairsTable = generateMatrix(Unique_List.length, 2, \"\");
values.forEach(function (row) {
for (i = 0; i < Unique_List.length; i++) {
if (row[0] === Unique_List[i]) {
pairsTable[i][0] = Unique_List[i];
pairsTable[i][1] = row[7];
}
}
})
// Fill last column in results table with corresponding File Ids
table.forEach(function (row, index) {
for (i = 0; i < pairsTable.length; i++) {
if (row[0] === pairsTable[i][0]) {
table[index][configFields + 1] = pairsTable[i][1];
}
}
})
// Populate results table with remaining group field values
values.forEach(function (row) {
configValues.forEach(function (configRow) {
if (row[4] === configRow[0] && configRow[2] !== \"\") {
for (i = 0; i <= Unique_List.length; i++) {
if (row[0] === Unique_List[i]) {
rowNum = i;
}
}
let val = row[6];
table[rowNum][configRow[2]] = val;
}
})
})
// Return results table
return table;
}
}
-
如果您将输入表和预期输出表添加到问题中,您的问题可以大大改善。 Tables 是比电子表格更好的选择来显示您的数据结构。如果您共享电子表格,请确保还添加工作表的图像以避免问题结束,因为此处的问题必须是 self contained。 Your email address can also be accessed by the public,当您共享 Google 文件时。
-
该功能实际上很慢吗?你似乎在使用数组,这意味着你已经越过了最大的乌龟陷阱。之后就是基本的js优化。从表面上看,我仍然不清楚每个函数的输入和预期输出是什么。您的问题可能更适合Code Review。我会注意到
unique可以用Set重写,它对唯一数据有更好的支持。如果有的话,我想将电子表格/数据流更改为不调用自定义函数 100 次。我还会使用Cache服务来避免重新计算相同的输入。 -
Edit 显示您如何调用每个函数并裁剪屏幕截图以仅显示数据(或在您已经显示表格时将其完全删除)。看来您正在为每一行调用
=func(A1)。如果是这种情况,请考虑重写它以接受如下数组:=func(A1:A100) -
@TheMaster 每个 \'RESULTS_\' 工作表只调用一次 getTable() 函数。然而,电子表格包含 50-100 个这些工作表,目前无法更改这种使用模式,因为对结果表数据执行了许多后续计算。
-
onEdittrigger 之类的东西不是更好吗?
标签: google-apps-script google-sheets