[英]Optimize iteration of 2-dimensional array
我正在嘗試優化 Google Apps 腳本,該腳本以反向(從下到上)迭代電子表格中的行。 腳本檢查行中的第一個單元格是否過去 15 天,並檢查第 12 列的字符串“是”,如果兩個條件都為真,則該行從一張紙移動到另一張紙。
我遇到的問題是我超過了分配的時間(6 分鍾),遍歷所有 2500 行的數據,並期望增長得更大。
我相信類似的問題已經在這里回答了很多次,但鑒於我目前的編程技能水平,我無法應用我在這里找到的解決方案。 任何幫助將不勝感激。
這是工作表的格式:
1st column 12th column
+-----------+-----/ /-----+-------------+
| Date | | Refunded? |
+-----------+-----/ /-----+-------------+
| 8/29/2017 | | YES |
+-----------+-----/ /-----+-------------+
| 9/26/2017 | | NO |
+-----------+-----/ /-----+-------------+
這是腳本:
function myFunction() {
// get compare date (15 days from current date
var compareDate = new Date().getTime() - (15 * (1000 * 60 * 60 * 24));
// get sheets in spreadsheet
var target = SpreadsheetApp.getActiveSpreadsheet().getSheets()[1];
var arr = [];
// get 1st sheet data
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheets()[0];
var values = sheet.getDataRange().getValues();
var r = values.length;
// logic
while (r >= 1) {
if (values[r] && values[r][0].getTime() < compareDate && values[r][12].toLowerCase() == "yes" ) {
arr.push(values[r])
sheet.deleteRow(r + 1)
}
r--;
}
target.getRange(target.getLastRow() + 1, 1, arr.length, arr[0].length).setValues(arr.reverse())
}
如果我注釋掉以下代碼行“sheet.deleteRow(r + 1)”,腳本幾乎立即完成,因此這似乎是減慢腳本執行速度的罪魁禍首。 是否有更有效的解決方案來解決這個問題?
不是通過迭代刪除一行,而是在腳本末尾使用deleteRows(rowPosition, howMany)一次刪除所有行。 這行代碼可能類似於以下內容:
sheet.deleteRows(2, values.length - 1);
深入了解 Ruben 關於一次刪除多行的想法。 在實際開始比較之前對數據進行排序是個好主意,這樣所有最舊的“是”值都位於底部。
為了檢查它,我設置了一個包含 25000 條記錄的工作表:
function fillSheet() {
var yesNo = ['yes', 'no'];
var array = [];
for (var i = 0; i < 25000; i++) {
array[i] = [];
var rand = yesNo[Math.floor(Math.random() * yesNo.length)];
array[i].push(new Date(2016, 1, i), i, i + 1, i + 2, i + 3, i + 4, i + 5, i + 6, i + 7, i + 8, i + 9, i + 10, rand);
}
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheets()[0];
sheet.getRange(2, 1, array.length, array[0].length).setValues(array);
}
然后我修改了您的函數,以便它首先按是/否和日期對數據范圍進行排序,然后進行檢查(這次從頂部開始)。
function myFunction() {
// get compare date (15 days from current date
var compareDate = new Date().getTime() - (15 * (1000 * 60 * 60 * 24));
// get sheets in spreadsheet
var target = SpreadsheetApp.getActiveSpreadsheet().getSheets()[1];
var arr = [];
// get 1st sheet data
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheets()[0];
var lastRow = sheet.getLastRow();
var lastCol = sheet.getLastColumn();
//sorting the range without the header row firstly by yes/no values and then by dates to make sure the oldest yes value are at the bottom and only then getting the values
sheet.getRange(2, 1, lastRow - 1, lastCol).sort([{column: 13, ascending: true}, {column: 1, ascending: false}]);
var values = sheet.getRange(2, 1, lastRow - 1, lastCol).getValues();
var r = 0;
var firstMatch = 0;
// logic
while (r < values.length) {
if (values[r] && values[r][0].getTime() < compareDate && values[r][12].toLowerCase() == "yes" ) {
//looking for the first match which will be used in deleting the rows
if (firstMatch === 0) {
firstMatch = r + 1;
}
else if (firstMatch > 0 && firstMatch > r) {
firstMatch = r + 1;
}
arr.push(values[r])
}
r++;
}
if (firstMatch > 0) {
target.getRange(target.getLastRow() + 1, 1, arr.length, arr[0].length).setValues(arr); //this will insert the array twice in my case anв i'm not sure why
sheet.deleteRows(firstMatch, values.length - firstMatch + 2); //+2 is empirical to make sure all rows are removed; not really sure where it comes from
sheet.getRange(2, 1, lastRow, lastCol).sort({column: 1, ascending: true});
}
}
這樣,運行大約需要 4 秒鍾。
不過有幾個小故障:
它嘗試將結果數組插入目標表兩次,但顯然不應該。 也許與我現在使用的 Vivaldi 瀏覽器有關,不知道。
經驗 firstMatch, values.length - firstMatch + 2 - 再次不確定為什么它應該 +2 但沒有它不會刪除最后 2 行。
希望它無論如何都有幫助。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.