【GASの始め方】繰り返し処理の「for文」を習得しよう | GASおじさんのブログ
GASの基本

【GASの始め方】繰り返し処理の「for文」を習得しよう

GASの基本

みなさんこんにちは!GASおじさんです。

GASでスプレッドシートを自由自在に操るためのスキル習得講座の第7回です。

前回の記事はこちら。

前回は各シートから売上を集計するというプログラムを作る過程で、関数について学びました。

関数という武器を手に入れたことで、冗長で無駄のあるコードをスマートなコードに書き直せるようになりました。

「これにて一件落着!」

といきたいところですが、実はまだとある課題が残っています。

今回はその課題を解決する新たな武器、繰り返し処理の制御構文「for文」について学習していきます。

関数について復習

関数のメリット

まずは関数について復習です。

関数とは、ひとことでいうと「一連の処理をひとまとめにしたもの」でしたね。

たとえば、以下のような処理1から処理5を3セット実行するというプログラムがあったとします。

function myFunction() {
  console.log('処理1を実行しました');
  console.log('処理2を実行しました');
  console.log('処理3を実行しました');
  console.log('処理4を実行しました');
  console.log('処理5を実行しました');

  console.log('処理1を実行しました');
  console.log('処理2を実行しました');
  console.log('処理3を実行しました');
  console.log('処理4を実行しました');
  console.log('処理5を実行しました');

  console.log('処理1を実行しました');
  console.log('処理2を実行しました');
  console.log('処理3を実行しました');
  console.log('処理4を実行しました');
  console.log('処理5を実行しました');
}

この書き方だと、myFunction関数の中身は 5行 x 3セット = 15行分のコードを書かなければなりません。

そこで、処理1から処理5をsampleFunc()という関数にまとめてあげることによって、myFunction関数の中身は3行書くだけで済むようになるのでした。

function myFunction() {
  sampleFunc();
  sampleFunc();
  sampleFunc();
}

function sampleFunc() {
  console.log('処理1を実行しました');
  console.log('処理2を実行しました');
  console.log('処理3を実行しました');
  console.log('処理4を実行しました');
  console.log('処理5を実行しました');
}

これが関数を使うことにより得られるメリットでした。

それでも残る課題

「15行が3行になる」というだけでも十分メリットは大きいですが、それでも課題は残ります。

もし仮に「処理1から処理5を3セット」ではなく、「処理1から処理5を100セット」繰り返せと言われた場合、コードは以下のようになります。

function myFunction() {
  sampleFunc(); // 1回目の呼び出し
  sampleFunc(); // 2回目の呼び出し
  sampleFunc(); // 3回目の呼び出し
  〜〜〜〜〜
  〜〜〜〜〜
  sampleFunc(); // 50回目の呼び出し
  sampleFunc(); // 51回目の呼び出し
  〜〜〜〜〜
  〜〜〜〜〜
  sampleFunc(); // 99回目の呼び出し
  sampleFunc(); // 100回目の呼び出し
}

function sampleFunc() {
  console.log('処理1を実行しました');
  console.log('処理2を実行しました');
  console.log('処理3を実行しました');
  console.log('処理4を実行しました');
  console.log('処理5を実行しました');
}

この場合、myFunction関数の中身は100行分のコードを書かなければなりません。

これは大変ですね。そこで、for文の出番です。

繰り返し処理のfor文

for文の概要

for文は「繰り返し処理の制御構文」とか「ループ文」と呼ばれる、プログラミングにおける基本的な構文です。

なぜ「for文」というのかというと、「〜のために」「~に対して」という前置詞「for」のそのままの意味に由来しており、「ある条件のために繰り返す」というところが語源となっております。

しかし、こう言われても最初はあまりピンと来ないと思うので、例の如く最初のうちは言葉自体には拘らず、「for文は繰り返し処理の制御構文」とまずは丸暗記しちゃってください。細かいニュアンスは手を動かしながら徐々に理解を深めていきましょう。

この「繰り返し処理」という概念は、PythonやRubyなど、GAS(JavaScript)以外のあらゆるプログラミング言語でも共通の基礎概念です。これを習得すると他の言語でも応用可能なので、ここでしっかり学んでおきましょう。

for文の種類

for文の種類には以下の2つがあります。

  • 数字で繰り返すfor文
  • 配列で繰り返すfor文

1個ずつ見ていきましょう。

数字で繰り返すfor文

1つ目は数字で繰り返すタイプのfor文です。

まずは以下のサンプルコードをコピペして実行してみてください。

function myFunction() {
  for(let i = 0; i < 5; i++) {
    console.log(i);
  }
}

こちらを実行すると、以下のような実行結果となります。

実行ログ画面に「0」「1」「2」「3」「4」と5回分の出力がされました。

これは、

  • 最初にlet i = 0で変数 i に 0 を代入する(初期化式)
  • i < 5という条件を満たす限り繰り返す(条件式)
  • ループするごとにi++で i を1ずつ足していく(増減式)

というfor文を書いているためにこのような結果となります。

このように、数字で繰り返すタイプのfor文は、「初期化式」「条件式」「増減式」という3つの式で成り立っています。それぞれの式はセミコロン「 ; 」で区切ります。

以下、それぞれの式について説明します。

① 初期化式

まず初期化式ではループ開始時の数値を決めます。

変数名は慣習的にiとすることが多いですが、別になんでもいいです。aとかbとかnumberとかindexとかでも構いません。

また、最初は0から始めることが多いですが、1でも2でも3でも構いません。

ためしに以下のようにlet i = 1として1から始めると、「1」「2」「3」「4」の4回のループになりますね。

② 条件式

条件式では文字通りループを何回繰り返すかの条件を決めます。

今回はi < 5という条件を指定しているので、iが0〜4の場合は条件を満たしますが、iが「5」になった瞬間に条件を満たさなくなるので、「0」「1」「2」「3」「4」の合計5回のループで終了するというわけですね。

なので当然、以下のように条件式をi < 10とすると10回繰り返すfor文となります。

function myFunction() {
  for(let i = 0; i < 10; i++) {
    console.log(i);
  }
}

③ 増減式

増減式ではループ1周するごとに変数iにどのような処理を施すかを指定します。

今回はi++としていますが、これはi += 1の書き換えです。

さらにi += 1i = i + 1の書き換えです。

ここで要注意なのは、プログラミングにおけるイコール(=)は「右辺を左辺に代入する」という意味でしたよね。なので、i = i + 1という数式は、「右辺のi + 1を左辺のiに代入する」という意味になります。

学生の時に習った算数や数学におけるイコールは「左辺と右辺は等しい」という意味だったので、i = i + 1のような数式は成り立たないし、見かけることのない数式だったと思います。そのため、プログラミング初心者のうちはi = i + 1のような書き方に慣れないと思います。実際私自身も最初はこのことで躓きました。

しかし、慣れてくればなんてことはありません。「先に右辺が実行されて、それが左辺に代入されるのだ」という流れをゆっくり追っていけば必ず理解できます。

それでは実際にループの流れを追ってみましょう。

  • まず1周目のループが終わるとi = i + 1が実行されます。
    • 最初iは「0」から始まるので、右辺は0 + 1を表します。
    • つまりi = 0 + 1という計算が行われ、その結果i = 1となります。
  • 次に2周目のループが終わると再度i = i + 1が実行されます。
    • 2周目のiは「1」なので、右辺は1 + 1を表します。
    • つまりi = 1 + 1という計算が行われ、その結果i = 2となります。

これが繰り返されていき、最終的にi = 5となりますが、そのときはじめて条件式i < 5を満たさなくなるため、そこでループが終了する、というわけですね。

繰り返し処理で1個ずつ足していくことを「インクリメントする」という言い方をしたりしますが、この「1個ずつ足す」という動作はプログラミングでは頻繁に出てくるため、特別な書き方としてi++という書き方が用意されています。

もちろん、1個ずつではなく2個ずつ足したいというときもあると思いますので、そのときは以下のように書きます。

function myFunction() {
  for(let i = 0; i < 10; i += 2) {
    console.log(i);
  }
}

こうすると実行結果は以下のようになります。

ログ出力は「0」「2」「4」「6」「8」となり、iは2個ずつ足されていることがわかりますね。


さて、以上が数字で繰り返すfor文の書き方の解説です。

まあ、このような解説を読むだけでは深い理解はできないので、実際にそれぞれの変数や数値をいろいろ書き換えて実行してみてください。

そうやって手を動かしながらガチャガチャと遊んでいるうちに、体の深いところで理解が進んでいくのを感じ取れると思います。

さて、以上の内容を踏まえて、sampleFunc()関数を100回繰り返せと言われた場合のプログラムを作成してみましょう。

function myFunction() {
  for(let i = 0; i < 100; i++){
    sampleFunc();
  }
}

function sampleFunc() {
  console.log('処理1を実行しました');
  console.log('処理2を実行しました');
  console.log('処理3を実行しました');
  console.log('処理4を実行しました');
  console.log('処理5を実行しました');
}

こうすると無事、「処理1から処理5までを100セット繰り返す」ということが実現できました。

for文を使う前は、myFunction関数の中に100行「sampleFunc();」と書かなければいけなかったところが、for文を使うことによってたった3行で済むようになりました。

どうでしょうか。for文の凄まじい威力を体感できたでしょうか?

配列で繰り返すfor文

for文にはもう一つ、配列で繰り返すタイプの書き方があります。

まずは以下のサンプルコードをコピペして実行してみてください。

function myFunction() {
  const names = ['sato', 'suzuki', 'takahashi'];
  for(const name of names) {
    console.log(name);
  }
}

こちらを実行してみると、以下のような結果となります。

実行ログ画面に、

  • sato
  • suzuki
  • takahashi

と出力されています。

これは、配列namesから1個ずつ要素を取り出して、変数nameに格納し、console.log(name);を実行するというfor文が動いているためこのような出力結果となります。

このように、配列で繰り返すタイプのfor文は、

for(const 変数 of 配列) {
  
}

という書き方をします。この書き方を「for-of文」と言ったりします。

こうすることで、配列の要素数だけ繰り返し処理をしてくれるfor文となります。

今回の場合、配列の要素数は['sato', 'suzuki', 'takahashi']なので3つですね。

したがってループは3周します。

  • まず1周目で'sato'が変数nameに格納される
  • 次に2周目で'suzuki'が変数nameに格納される
  • 次に3周目で'takahashi'が変数nameに格納される

例のごとく変数名は任意の文字列でOKなので、たとえばconst a of namesのようにして動かすことも可能ですが、const name of namesとするほうがわかりやすいですよね。なので通常は変数名には配列の単数系の名前を与えることが多いです。

for(const 単数系 of 複数形) という形になることが多い

以上、配列で繰り返すfor文の解説でした。

再度、応用問題を解いてみる

それでは、for文という武器を手に入れたところで、あらためて前回の応用問題の解答例を作成してみましょう。

解答例その5: 配列とfor文を使う

function setTotalSales() {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const sheet = ss.getSheetByName('集計');
  const companies = ['A社', 'B社', 'C社'];
  const values = [];
  for(const company of companies){
    values.push([getTotalSales(company)]);
  }
  sheet.getRange(2, 2, values.length, values[0].length).setValues(values);
}

function getTotalSales(sheetName) {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const sheet = ss.getSheetByName(sheetName);
  const lastRow = sheet.getLastRow();
  return sheet.getRange(lastRow, 2).getValue();
}

このコードをコピペしてsetTotalSales関数を実行してみましょう。

すると無事、集計シートのB列に各社の売上合計が集計されました。

プログラムの流れを追ってみよう

それではプログラムの流れを追っていきましょう。重要なポイントをかいつまんで説明していきます。

function setTotalSales() {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const sheet = ss.getSheetByName('集計');
  const companies = ['A社', 'B社', 'C社'];
  const values = [];
  for(const company of companies){
    values.push([getTotalSales(company)]);
  }
  sheet.getRange(2, 2, values.length, values[0].length).setValues(values);
}
  • 4行目で配列companiesを定義する
  • 5行目で空の配列valuesを定義する
  • 6〜8行目でfor文が3周する(A社, B社, C社)
    • for文の中で各社の合計売上がvaluesにpushされる
    • その結果for文終了時に二次元配列ができあがる
  • for文終了後、9行目で二次元配列valuesがsetValuesされる

さて、今回新たにpushというメソッドが出てきました。

配列に対してpushメソッドを使うと、配列に要素を追加することができます。

以下のサンプルコードを実行してみてください。

function myFunction() {
  const names = ['sato', 'suzuki', 'takahashi'];
  console.log(names);
  names.push('tanaka');
  console.log(names);
}

こちらを実行すると、以下のような実行結果となります。

3行目のログ出力は['sato', 'suzuki', 'takahashi']

となっているのに対し、

5行目のログ出力は['sato', 'suzuki', 'takahashi', 'tanaka']

となっています。

これは、4行目で配列namesに対して'tanaka'をpushしているからです。

このように、配列に対してpushメソッドを使うと、配列に要素を追加することができるのです。

これを利用して、最初は空の配列だったvaluesに、for文が回るごとに各社の売上が追加されていく、という仕組みになっているのですね。

const companies = ['A社', 'B社', 'C社'];
const values = [];
for(const company of companies){
  values.push([getTotalSales(company)]);
}
  • 最初valuesは空の配列になっている
    • values = []
  • for文1周目でvaluesにA社の売上がpushされる
    • values = [[60000]]
  • for文2周目でvaluesにB社の売上がpushされる
    • values = [[60000], [75000]]
  • for文3周目でvaluesにC社の売上がpushされる
    • values = [[60000], [75000], [100000]]

このようにして、for文終了後には、

const values = [
  [60000],
  [75000],
  [100000],
];

という二次元配列ができあがっているという仕組みです。

このように、最初に空の配列を用意してfor文とpushメソッドで二次元配列を生成するやり方は、スプレッドシート操作では頻繁に使われる手法なので、ここはしっかり理解に努めるようにしましょう。

まとめ

以上、繰り返し処理のfor文について解説しました。

for文は非常に強力な武器です。

同じことを何度も繰り返すような単調作業を人間がこなしていると、時間がかかったり、途中でミスがでたりというようなことが頻発します。

しかし、for文を使いこなすことができれば、そのような作業をミスなく一瞬で終わらせることができます。

プログラミングを勉強する醍醐味はfor文にあるといっても過言ではありません。ぜひ今回の記事を何度も読み返して、for文の習得に励んでください!

次回はループさせる配列を自動生成する方法について考えていきます!

連載目次: GASでスプレッドシートを自由自在に操るためのスキル習得講座

  1. 【GASの始め方】まずはスプレッドシートの操作から始めてみよう
  2. 【GASの始め方】setValuesで複数のセルに値を入力しよう
  3. 【GASの始め方】getValueで値を取得してsetValueで入力しよう
  4. 【GASの始め方】getValuesで複数のセルの値を取得しよう
  5. 【GASの始め方】getValuesして別のシートにsetValuesしよう
  6. 【GASの始め方】応用問題で関数について学ぼう
  7. 【GASの始め方】繰り返し処理の「for文」を習得しよう
  8. 【GASの始め方】flat()でループさせる配列を自動生成しよう
  9. 【GASの始め方】for文とif文でデータ抽出して配列を生成しよう
  10. 【GASの始め方】TextFinderで行と列を特定しよう
  11. 【GASの始め方】オブジェクトとメソッドについて学ぼう
  12. 【GASの始め方】リファクタリングで生成AIを活用しよう

GASを勉強するならこちら!

▼オススメ書籍はこちら!

スポンサーリンク
GASおじさんをフォローする

コメント

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