如果学分少于x,我正在使用以下脚本从Google电子表格的学生循环中添加文件行。该脚本运行良好,但是由于每天都在添加电子表格中的数据,因此该脚本引发“超出最大执行时间”错误(我们有2000多个文件)。由于我是脚本新手,所以我不知道如何优化代码。
有人可以帮助我优化代码或任何解决方案,以使执行时间少于5分钟。每次与电子邮件进行比较时,都必须将其与许多电子邮件进行比较。请帮忙!
function updated() {
//Final file data (Combined)
var filecombined = SpreadsheetApp.openById("XXXXXXXXXX");
var sheet2 = filecombined.getSheets();
//Folder with all the files
var parentFolder = DriveApp.getFolderById("YYYYYYYYYYYY");
var files = parentFolder.getFiles();
//Current Date
var fecha = new Date();
//Path for each file in the folder
while (files.hasNext()) {
var idarchivo = files.next().getId();
var sps = SpreadsheetApp.openById(idarchivo);
var sheet = sps.getSheetByName('STUDENT PROFILE');
var data = sheet.getDataRange().getValues();
var credits = data[5][1];
//Flat; bandera:1 (new row), bandera:2 (update row)
var bandera = 1;
//Take data from final file (Combined)
var data2 = sheet2[0].getDataRange().getValues();
//If credits are less than X: write
if (credits < 120) {
var email = data[2][1];
var lastrow = filecombined.getLastRow();
var u = 0;
//comparison loop by email, if found it, update and exit the loop
while (u < lastrow) {
u = u + 1;
if (email == data2[u - 1][1]) {
sheet2[0].getRange(u, 3).setValue(credits);
sheet2[0].getRange(u, 4).setValue(fecha);
u = lastrow;
bandera = 2;
}
}
//if that email does not exist, write a new row
if (bandera == 1) {
var nombre = data[0][1];
sheet2[0].getRange(lastrow + 1, 1).setValue(nombre);
sheet2[0].getRange(lastrow + 1, 2).setValue(email);
sheet2[0].getRange(lastrow + 1, 3).setValue(credits);
sheet2[0].getRange(lastrow + 1, 4).setValue(fecha);
}
}
}
SpreadsheetApp.flush();
}
答案 0 :(得分:2)
发问者的代码需要4到6分钟才能运行,并且收到错误Exceeded maximum execution time
。
以下答案仅基于发问者提供的代码。我们没有有关“文件组合”电子表格,其大小和触发器的任何信息。除了我们知道这些文件有2,000个以外,我们对各种学生电子表格,它们的大小等也一无所知。我们不知道该例程的运行频率,也不知道有多少学生的学分少于120。
getvalues
和setvalues
语句非常昂贵;通常每个0.2秒。发问者代码包括各种这样的语句-有些是不可避免的,而另一些则不是。
在优化此代码时,我做了两个主要更改。
1-我移动了第27行var data2 = sheet2[0].getDataRange().getValues();
该行仅需要执行一次,而在各种“文件合并”命令之后,我将其重新定位在代码的顶部。就目前而言,该行针对每个学生电子表格执行一次;这可能导致几分钟的执行时间。
2)我将某些setvalue
命令转换为一个数组,然后在处理结束时仅一次更新了该数组中的“文件组合”电子表格。根据低学分的学生的数量以及尚未在“文件组合”表中的学生的数量,这可能是一笔可观的节省。
受影响的代码是第47至50行。
line47: sheet2[0].getRange(lastrow+1, 1).setValue(nombre);
line48: sheet2[0].getRange(lastrow+1, 2).setValue(email);
line49: sheet2[0].getRange(lastrow+1, 3).setValue(credits);
line50: sheet2[0].getRange(lastrow+1, 4).setValue(fecha);
在第38和39行也执行了setvalue
命令(如果学生已经在“文件组合”电子表格中),但是我选择保持原样。如上所述,我们不知道会有多少这样的学生,而这些setvalue
命令的成本可能还是很小的。直到清楚这一点,并考虑到其他时间的节省,我选择将它们保持原样。
function updated() {
//Final file data (Combined)
var filecombined = SpreadsheetApp.openById("XXXXXXXXXX");
var sheet2 = filecombined.getSheets();
//Take data from final file (Combined)
var data2 = sheet2[0].getDataRange().getValues();
// create some arrays
var Newdataarray = [];
var Masterarray = [];
//Folder with all the files
var parentFolder = DriveApp.getFolderById("YYYYYYYYYYYY");
var files = parentFolder.getFiles();
//Current Date
var fecha = new Date();
//Path for each file in the folder
while (files.hasNext()) {
var idarchivo = files.next().getId();
var sps = SpreadsheetApp.openById(idarchivo);
var sheet = sps.getSheetByName('STUDENT PROFILE');
var data = sheet.getDataRange().getValues();
var credits = data[5][1];
//Flat; bandera:1 (new row), bandera:2 (update row)
var bandera = 1;
//If credits are less than X: write
if (credits < 120){
var email = data[2][1];
var lastrow = filecombined.getLastRow();
var u = 0;
//comparison loop by email, if found it, update and exit the loop
while (u < lastrow) {
u = u + 1;
if (email == data2[u-1][1]){
sheet2[0].getRange(u, 3).setValue(credits);
sheet2[0].getRange(u, 4).setValue(fecha);
u = lastrow;
bandera = 2;
}
}
//if that email does not exist, write a new row
if(bandera == 1){
var nombre = data[0][1];
Newdataarray = [];
Newdataarray.push(nombre);
Newdataarray.push(email);
Newdataarray.push(credits);
Newdataarray.push(fecha);
Masterarray.push(Newdataarray);
}
}
}
// update the target sheet with the contents of the array
// these are all adding new rows
lastrow = filecombined.getLastRow();
sheet2[0].getRange(lastrow+1, 1, Masterarray.length, 4);
sheet2[0].setValues(Masterarray);
SpreadsheetApp.flush();
}
答案 1 :(得分:0)
正如我在my comment中提到的那样,最大的问题是,当您可以使用much faster查找功能时,您反复在数组中搜索值。
// Create an object that maps an email address to the (last) array
// index of that email in the `data2` array.
const knownEmails = data2.reduce(function (acc, row, index) {
var email = row[1]; // email is the 2nd element of the inner array (Column B on a spreadsheet)
acc[email] = index;
return acc;
}, {});
然后,您可以通过尝试获取其值来确定data2
中是否存在电子邮件:
// Get this email's index in `data2`:
var index = knownEmails[email];
if (index === undefined) {
// This is a new email we didn't know about before
...
} else {
// This is an email we knew about already.
var u = ++index; // Convert the array index into a worksheet row (assumes `data2` is from a range that started at Row 1)
...
}
要了解我们如何从knownEmails
构建data2
,您可能会发现Array#reduce
上的文档很有帮助。