【GAS入門】スクリプトが重い・タイムアウトする原因!「ループのネスト(二重ループ)」の落とし穴

自動化・GAS

「GASを使って2つのデータを比較するスクリプトを書いたのに、実行が終わらない…」
「しばらく待っていると『実行時間が上限を超えました』というエラーが出てしまう」

GASで業務効率化を進めていると、必ずと言っていいほどぶつかるのがこの「6分の壁(タイムアウト)」です。
特に、複数店舗のデータなどを突き合わせる処理でこのエラーが出る場合、原因の9割は「ループのネスト(二重ループ)」という書き方にあります。

やりたい処理のイメージはできているのに、なぜかシステムが止まってしまう。この記事では、そんなプログラミング初級者の方が陥りやすい「ループのネスト」の正体と、なぜそれがダメなのかを、日常の業務に例えてわかりやすく解説します。

1. ループのネスト(二重ループ)とは?

2つのデータを比較しようとしたとき、一番最初に思いつき、そして一番やってしまいがちなのが「for文の中に、さらにfor文を書く」という方法です。
これを「ループのネスト」と呼びます。

一見すると直感的でわかりやすいのですが、データ量が増えると恐ろしいほど処理が重くなるという致命的な弱点があります。日常の業務に例えて、この動きを見てみましょう。

たとえば、「かえで薬局」「イチョウ薬局」の在庫リスト(配列)を比較して、同じ薬品がないか探したいとします。

▼ ループのネストの動き

「かえで薬局」のリストから、1つ目の薬(例:ロキソプロフェン)を見る。

「イチョウ薬局」のリストを一番上から下まで全部探して、ロキソプロフェンがあるか確認する。

次に「かえで薬局」のリストから、2つ目の薬(例:ムコスタ)を見る。

また「イチョウ薬局」のリストを一番上に戻って、下まで全部探して確認する。

(これを最後まで繰り返す…)

2. GASのコードで見る「ネスト」の落とし穴

実際のGASのコードでは、以下のように書かれている状態です。

// ❌ 処理が極端に重くなる「ネスト(二重ループ)」の例
for (let i = 0; i < kaedeData.length; i++) { 
  // かえで薬局のデータを1行ずつ確認するループ
  
  for (let j = 0; j < ginkgoData.length; j++) { 
    // そのたびに、イチョウ薬局の全データを最初から最後まで探すループ
    
    if (kaedeData[i][0] === ginkgoData[j][0]) {
      // 薬品IDが一致したときの処理
    }
  }
}

「かえで薬局のデータを回すループ(i)」の中に、「イチョウ薬局のデータを回すループ(j)」がすっぽりと入ってしまっています。

これがネスト状態です。

3. なぜエラー(タイムアウト)になるのか?

では、なぜこの書き方をするとシステムが止まってしまうのでしょうか。

答えは「作業の回数が掛け算で爆発的に増えるから」です。

もし、それぞれの薬局に薬が「1,000品目」ずつあった場合を計算してみましょう。

かえで薬局の1品目を探すために、いちょう薬局のリストを1,000回見直します。

  • 1,000品目 × 1,000回 = 合計 100万回

100万回の確認作業。人間の手作業なら「絶対にそんな非効率な探し方はしない!」と怒られてしまうようなやり方ですよね。

実はパソコン(GAS)にとっても、これは非常にしんどい作業です。データが数千件、数万件と増えた瞬間、計算回数は1,000万回、1億回と跳ね上がり、「もう限界!」と途中で力尽きてエラーになってしまうのです。

4. ループのネストからの脱却に向けて

VLOOKUP関数が重いのと同じ理由で、データを「上から下まで毎回探す」というアプローチには限界があります。

この問題を解決するためには、具体的には、毎回リストを下まで探すのではなく、探される側のデータをあらかじめ「IDを見出しにした辞書(オブジェクト {})」に変換しておくというテクニックを使います。

辞書になっていれば、100万回も探し回る必要はなく、「見出しをパッと引く」という1回の動作でデータを見つけることができます。

「自分の書いたコードが重いな」と感じたら、まずはfor文の中にfor文が入っていないかチェックしてみてください。ループのネストを卒業することが、GASで実用的なシステムを作るための大きな第一歩になります。