Google 用于在大型列表中查找和更新数据的表格脚本非常慢
Google Sheets script to find & update data on a large list is very slow
希望有人可以让我走上正确的道路。 (我认为这归结为我不了解如何使用客户端数组?)。
我拼凑的脚本在客户列表中查找匹配的名称,然后根据我在另一个选项卡上输入的数据更新一堆列。最后,我希望能够完全从另一个 sheet 执行此操作,但现在循环整个列表需要 3-4 分钟。我怀疑我需要做的是获取整个数据集,对其进行修改,然后设置新值,但我不确定我是否正确理解了问题。
function UpdateEntry() {
var client_name=SpreadsheetApp.getActive().getSheetByName("Rolodex!C2").getValue()
var addr=SpreadsheetApp.getActive().getSheetByName("Rolodex!C4").getValue()
var client_phone=SpreadsheetApp.getActive().getRange("Rolodex!E4").getValue()
var client_fax=SpreadsheetApp.getActive().getRange("Rolodex!E6").getValue()
var client_WWW=SpreadsheetApp.getActive().getRange("Rolodex!E7").getValue()
var data=SpreadsheetApp.getActive().getSheetByName("Rolodex").getRange("C4").getValue()
var key=SpreadsheetApp.getActive().getSheetByName("Rolodex").getRange("C2").getValue()
var database=SpreadsheetApp.getActive().getSheetByName("Database")
var datalength=database.getDataRange().getValues().length
database.getDataRange().getValues()
for (var i = 1;[i]<=datalength ; i++){
Logger.log('i: ' + i)
if(database.getRange([i],[1]).getValue() == client_name){
database.getRange([i],2).setValue(addr)
database.getRange([i],3).setValue(client_phone)
database.getRange([i],4).setValue(client_fax)
database.getRange([i],5).setValue(client_WWW)
}
}
}
我相信你的现状和目标如下。
- 您的脚本运行良好。但是工艺成本高
- 您想降低脚本的处理成本。
修改点:
getValue()
是ClassRange的方法。但在var client_name=SpreadsheetApp.getActive().getSheetByName("Rolodex!C2").getValue()
处,getValue
被用作ClassSheet的方法。在这种情况下,我认为错误发生在脚本的第一行。
- 根据你的问题,我认为
getSheetByName
可能是 getRange
。
SpreadsheetApp.getActive()
声明一次即可使用
client_name,addr,client_phone,client_fax,client_WWW
的值可以由一个 getValues
检索。
data
和 key
未使用。
database.getDataRange().getValues()
行未使用。
getValue
和setValue
在循环中使用。
- 在这种情况下,首先使用
getValues
从 sheet 中检索值。然后,创建要放入 sheet 的值,然后使用 setValues
. 将创建的值放入 sheet
- 这里作为重点,当使用
setValues
时,要求所有列的长度相同。请注意这一点。
当以上几点反映到你的脚本中,就会变成下面这样。
修改后的脚本:
function UpdateEntry() {
var ss = SpreadsheetApp.getActive();
// 1. Retrieve values of client_name, addr, client_phone, client_fax, client_WWW from Rolodex sheet.
var sheet = ss.getSheetByName("Rolodex");
var [[client_name],,[addr,,client_phone],,[,,client_fax],[,,client_WWW]] = ss.getRange("Rolodex!C2:E7").getValues();
var ar = [client_name, addr, client_phone, client_fax, client_WWW];
var arLength = ar.length;
// 2. Retrieve values from database sheet.
var database = ss.getSheetByName("Database");
var values = database.getDataRange().getValues();
var columnLength = values[0].length;
// 3. Create values for putting to Database sheet using the values retrieved from Rolodex sheet.
var res;
if (columnLength > arLength) {
res = values.map(r => r[0] == client_name ? ar.concat(r.slice(arLength)) : r);
} else {
res = values.map(r => r[0] == client_name ? ar : r.concat(Array(arLength - columnLength).fill("")));
}
// 4. Put the values to Database sheet.
database.getRange(1, 1, res.length, res[0].length).setValues(res);
}
注:
当您使用此修改后的脚本时,请在脚本编辑器中启用 V8 运行时。
如果上面修改的脚本不是您期望的结果,您当前的脚本可能不是您期望的结果。如果我的理解是正确的,你能提供你期望的样本输入和输出吗?借此,我想确认一下。
参考文献:
希望有人可以让我走上正确的道路。 (我认为这归结为我不了解如何使用客户端数组?)。
我拼凑的脚本在客户列表中查找匹配的名称,然后根据我在另一个选项卡上输入的数据更新一堆列。最后,我希望能够完全从另一个 sheet 执行此操作,但现在循环整个列表需要 3-4 分钟。我怀疑我需要做的是获取整个数据集,对其进行修改,然后设置新值,但我不确定我是否正确理解了问题。
function UpdateEntry() {
var client_name=SpreadsheetApp.getActive().getSheetByName("Rolodex!C2").getValue()
var addr=SpreadsheetApp.getActive().getSheetByName("Rolodex!C4").getValue()
var client_phone=SpreadsheetApp.getActive().getRange("Rolodex!E4").getValue()
var client_fax=SpreadsheetApp.getActive().getRange("Rolodex!E6").getValue()
var client_WWW=SpreadsheetApp.getActive().getRange("Rolodex!E7").getValue()
var data=SpreadsheetApp.getActive().getSheetByName("Rolodex").getRange("C4").getValue()
var key=SpreadsheetApp.getActive().getSheetByName("Rolodex").getRange("C2").getValue()
var database=SpreadsheetApp.getActive().getSheetByName("Database")
var datalength=database.getDataRange().getValues().length
database.getDataRange().getValues()
for (var i = 1;[i]<=datalength ; i++){
Logger.log('i: ' + i)
if(database.getRange([i],[1]).getValue() == client_name){
database.getRange([i],2).setValue(addr)
database.getRange([i],3).setValue(client_phone)
database.getRange([i],4).setValue(client_fax)
database.getRange([i],5).setValue(client_WWW)
}
}
}
我相信你的现状和目标如下。
- 您的脚本运行良好。但是工艺成本高
- 您想降低脚本的处理成本。
修改点:
getValue()
是ClassRange的方法。但在var client_name=SpreadsheetApp.getActive().getSheetByName("Rolodex!C2").getValue()
处,getValue
被用作ClassSheet的方法。在这种情况下,我认为错误发生在脚本的第一行。- 根据你的问题,我认为
getSheetByName
可能是getRange
。
- 根据你的问题,我认为
SpreadsheetApp.getActive()
声明一次即可使用client_name,addr,client_phone,client_fax,client_WWW
的值可以由一个getValues
检索。data
和key
未使用。database.getDataRange().getValues()
行未使用。getValue
和setValue
在循环中使用。- 在这种情况下,首先使用
getValues
从 sheet 中检索值。然后,创建要放入 sheet 的值,然后使用setValues
. 将创建的值放入 sheet
- 这里作为重点,当使用
setValues
时,要求所有列的长度相同。请注意这一点。
- 在这种情况下,首先使用
当以上几点反映到你的脚本中,就会变成下面这样。
修改后的脚本:
function UpdateEntry() {
var ss = SpreadsheetApp.getActive();
// 1. Retrieve values of client_name, addr, client_phone, client_fax, client_WWW from Rolodex sheet.
var sheet = ss.getSheetByName("Rolodex");
var [[client_name],,[addr,,client_phone],,[,,client_fax],[,,client_WWW]] = ss.getRange("Rolodex!C2:E7").getValues();
var ar = [client_name, addr, client_phone, client_fax, client_WWW];
var arLength = ar.length;
// 2. Retrieve values from database sheet.
var database = ss.getSheetByName("Database");
var values = database.getDataRange().getValues();
var columnLength = values[0].length;
// 3. Create values for putting to Database sheet using the values retrieved from Rolodex sheet.
var res;
if (columnLength > arLength) {
res = values.map(r => r[0] == client_name ? ar.concat(r.slice(arLength)) : r);
} else {
res = values.map(r => r[0] == client_name ? ar : r.concat(Array(arLength - columnLength).fill("")));
}
// 4. Put the values to Database sheet.
database.getRange(1, 1, res.length, res[0].length).setValues(res);
}
注:
当您使用此修改后的脚本时,请在脚本编辑器中启用 V8 运行时。
如果上面修改的脚本不是您期望的结果,您当前的脚本可能不是您期望的结果。如果我的理解是正确的,你能提供你期望的样本输入和输出吗?借此,我想确认一下。