先日恥ずかしげもなくアップした家計簿のコードですが、少しずつ変更を加えて九龍城砦のごとき体裁になっています。
(いらすとやってすごいですね・・・)
スプレッドシートの特定の行・列の最終行・列番号を取得する関数をコピペ流用していたのですが、これがめちゃくちゃ重い。
この関数をかますだけで1~2分処理時間が増えてしまいました。
問題のコードがこれ
// この関数超重い
function getLastRow(sheet,col){
var last_row = sheet.getLastRow();
for(var i = last_row; i >= 1; i--){
if(sheet.getRange(i, col).getValue() != ''){
return i
break;
}
}
}
// この関数超重い
function getLastCol(sheet,row){
var last_row = sheet.getLastRow();
for(var i = last_row; i >= 1; i--){
if(sheet.getRange(row, i).getValue() != ''){
return i
break;
}
}
}
分かる方はぱっと見わかると思いますが、遅い理由はGASのAPI呼び出し回数です。
具体的に言うと、getLastRow()、getRange()とgetValue()がGASのAPIです。
これがfor文の中でシートの最大行数・最大列数回繰り返し呼ばれていたというわけです。
GASをやっている人の間ではAPIの実行を極力減らすというのが常識(?)となっているようで、この関数は最大行数・最大列数をごく小さくしたシート以外ではイケてないコードだったというわけです。
ではどうするのかですが、単にシートの値を二次元配列に入れてjs側で処理をすることをベースにやっていきます。
つまりこういうコードにすれば2秒くらいで処理が終わるようになります。
//列の値を全て取得
const row_values = aggregation_sheet.getRange('A:A').getValues();
//空白の要素を除いた長さを取得
const last_row = row_values.filter(String).length;
//行の値を全て取得
const col_values = aggregation_sheet.getRange('1:1').getValues();
//空白の要素を除いた長さを取得
const last_col = col_values.flat().filter(String).length;
もはや関数ですらありません。
特定列・行を配列に入れ、空白ではない要素の長さを取得しています。
列をこの方法で取得する場合は、二次元配列として取得されるので、flat()で1次元配列に加工してあげてから長さを取得します。
私のニーズではこれで事足りました。
これで満たせないニーズは、取得したい行や列の中に空白がある場合でしょうか。lengthの値が変わってしまいますからね。
ほかにも色々増築していますので、小出しになりますがアップしていきたいと思っています。
よろしくお願いします。
コメント
[…] 追記:この記事にあるコードだと遅いので早くしました。作ったGASがとっても遅かったので早くした […]