作ったGASがとっても遅かったので早くした

GAS

先日恥ずかしげもなくアップした家計簿のコードですが、少しずつ変更を加えて九龍城砦のごとき体裁になっています。
(いらすとやってすごいですね・・・)

スプレッドシートの特定の行・列の最終行・列番号を取得する関数をコピペ流用していたのですが、これがめちゃくちゃ重い。
この関数をかますだけで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の値が変わってしまいますからね。

ほかにも色々増築していますので、小出しになりますがアップしていきたいと思っています。
よろしくお願いします。

コメント

  1. […] 追記:この記事にあるコードだと遅いので早くしました。作ったGASがとっても遅かったので早くした […]

タイトルとURLをコピーしました