見出し画像

【GAS初心者講座#3】関数と配列入門 ー 処理を部品化してデータをまとめて扱う

こんにちは!ノンプロ研でGASコースのTAをしているTaroです。

今回は、GAS(Google Apps Script)の「関数」と「配列」について、初学者の方でも理解できるように丁寧に解説していきます。この記事は、ノンプロ研初心者講座【GASコース】第3回の内容をもとに作成しています。

この記事で学べること

  • 関数:処理を「部品化」して再利用する技術

  • 配列:複数のデータを「まとめて」扱う技術

  • アロー関数:より簡潔に関数を書く方法

  • 二次元配列:表形式のデータを扱う方法

最初に伝えたい大切なこと:
今回学ぶ「関数」と「配列」は、プログラミングの中級編に入る第一歩です。「ちょっと難しいかも...」と感じるかもしれませんが、大丈夫。

料理で例えるなら:

  • 関数:「カレーの作り方」というレシピを一度書いておけば、何度でも同じカレーが作れる

  • 配列:材料を「野菜」「肉」とバラバラに管理するより、「買い物リスト」として一つにまとめる

この2つができるようになると、プログラムが一気に「実用レベル」になります。


前回のおさらい

第2回では、プログラムの3つの基本構造を学びました:

  1. 順次:上から順番に実行

  2. 選択:条件によって処理を変える(if文、switch文)

  3. 反復:同じ処理を繰り返す(for文、while文)

これらを使って、「100件のデータをチェックして、条件に合うものだけ処理する」といったことができるようになりましたね。

今回学ぶ「関数」と「配列」を組み合わせると、さらに強力になります。


第1部:関数 - 処理を「部品化」して再利用する

関数とは?

関数とは、一連の処理をまとめて名前を付けたものです。

実は、あなたはもう関数を使っています:

function myFunction() {
  console.log('Hello!');
}

このmyFunctionが関数です。functionという宣言で、処理をまとめているんです。

なぜ関数が必要?

同じ処理を何度も書くのは大変ですよね。例えば:

// 悪い例:同じ処理を3回書いている
function myFunction() {
  console.log('Hello!');
  console.log('Good Bye.');
  
  console.log('Hello!');
  console.log('Good Bye.');
  
  console.log('Hello!');
  console.log('Good Bye.');
}

関数を使えば:

// 良い例:関数で処理をまとめる
function myFunction() {
  sayHello();
  sayHello();
  sayHello();
}

function sayHello() {
  console.log('Hello!');
  console.log('Good Bye.');
}

関数の3つのメリット:

  1. 再利用できる:一度書けば何度でも使える

  2. 修正が楽:関数の中身を変えれば、呼び出している全ての場所が変わる

  3. 読みやすい:処理に名前が付いているので、何をしているかわかりやすい


関数の定義と呼び出し

関数の定義:

function 関数名() {
  // 処理
}

関数の呼び出し:

関数名();

実際に試してみよう(演習3-01):

function myFunction3_01() {
  sayHello();
  console.log('Good Bye.');
}

function sayHello() {
  console.log('Hello!');
}

実行すると:

Hello!
Good Bye.

処理の流れ:

  1. myFunction3_01()が実行される

  2. sayHello()を呼び出す → Hello!と出力

  3. console.log('Good Bye.')を実行 → Good Bye.と出力

重要なポイント:

  • 関数名は「動詞」で始めるとわかりやすい(例:sayHello, calcArea, sendEmail)

  • プロジェクト内で関数名は重複しないように!


引数と戻り値 - 関数をもっと便利に

関数には2つの重要な概念があります:

  • 引数(ひきすう):関数に渡す値

  • 戻り値(もどりち):関数から受け取る値

料理で例えるなら:

  • 引数:材料(「りんご」を渡す)

  • 関数:調理(りんごを切って焼く)

  • 戻り値:完成品(「アップルパイ」を受け取る)

引数:関数に値を渡す

構文:

// 関数の定義
function 関数名(仮引数1, 仮引数2, ...) {
  // 処理
}

// 関数の呼び出し
関数名(引数1, 引数2, ...);

用語の整理:

  • 引数:関数を呼び出すときに渡す実際の値

  • 仮引数:関数の定義で受け取る値の「箱」

例:長方形の面積を計算する関数

function myFunction() {
  console.log(calcArea(3, 4));  // 12
}

function calcArea(x, y) {
  return x * y;
}

処理の流れ:

  1. calcArea(3, 4)を呼び出す

  2. 引数3が仮引数xに、引数4が仮引数yに渡される

  3. x * y(3 × 4 = 12)を計算

  4. 結果を戻り値として返す


戻り値:関数から値を受け取る

構文:

function 関数名(仮引数1, 仮引数2, ...) {
  // 処理
  return 戻り値;
}

returnは「この値を返す」という命令です。

実際に試してみよう(演習3-02):

function myFunction3_02() {
  console.log(calcArea(3, 4));  // 12
}

function calcArea(x, y) {
  return x * y;
}

returnの重要ポイント:

  • returnを実行すると、その時点で関数の処理が終了する

  • returnの後の処理は実行されない

function test() {
  console.log('1つ目');
  return 'OK';
  console.log('2つ目');  // これは実行されない!
}

演習:関数を自分で作ってみよう

演習3-03:余りを計算する関数

2つの整数を引数として受け取り、xをyで割ったときの余りを戻り値として返す関数を作成しましょう。

解答例:

function myFunction3_03() {
  console.log(calcRemainder(10, 3));  // 1
}

function calcRemainder(x, y) {
  return x % y;
}

演習3-04:偶数判定関数

整数を引数として受け取り、その値が偶数ならtrue、そうでないならfalseを戻り値として返す関数を作成しましょう。

解答例:

function myFunction3_04() {
  console.log(isEven(4));   // true
  console.log(isEven(5));   // false
}

function isEven(x) {
  return x % 2 === 0;
}

ポイント:

  • 関数名をisEven(偶数かどうか)とすることで、戻り値がブール型だとわかる

  • return x % 2 === 0;は、条件式の結果(trueかfalse)をそのまま返している


アロー関数:もっと簡潔に書く方法

ここからは少し応用編です。アロー関数という、関数をもっと簡潔に書く方法を学びます。

従来の書き方:

function calcArea(x, y) {
  return x * y;
}

アロー関数の書き方:

const calcArea = (x, y) => {
  return x * y;
};

「あれ?長くなってない?」と思ったかもしれません。でも、アロー関数にはもっと便利な使い方があるんです。


アロー関数の基本構文

基本形:

(仮引数1, 仮引数2, ...) => {
  // 処理
  return 戻り値;
}

関数を定数に代入する:

const 関数名 = (仮引数1, 仮引数2, ...) => {
  // 処理
  return 戻り値;
};

実際に試してみよう(演習3-05):

function myFunction3_05() {
  const sayHello = () => {
    console.log('Hello!');
  };
  
  sayHello();
  console.log('Good Bye.');
}

結果:

Hello!
Good Bye.

ポイント:

  • 関数を変数や定数に代入できる

  • 代入した定数名で関数を呼び出せる


アロー関数の省略記法

アロー関数には、コードを短くできる便利な省略ルールがあります。

省略ルール1:仮引数が1つだけなら、丸かっこを省略できる

// 通常
const square = (x) => {
  return x * x;
};

// 省略
const square = x => {
  return x * x;
};

省略ルール2:処理がreturnだけなら、returnと波括弧を省略できる

// 通常
const square = x => {
  return x * x;
};

// 省略
const square = x => x * x;

実際に試してみよう(演習3-06):

function myFunction3_06() {
  const calcArea = x => x ** 2;
  console.log(calcArea(3));  // 9
}

こんなに短くなりました!

// function宣言
function calcArea(x) {
  return x ** 2;
}

// アロー関数(省略なし)
const calcArea = (x) => {
  return x ** 2;
};

// アロー関数(省略あり)
const calcArea = x => x ** 2;

function宣言とアロー関数、どっちを使う?

function宣言が適している場合:

  • トップレベルの関数(プロジェクト全体で使う関数)

  • 長い処理を書く関数

  • スクリプトエディタで直接実行する関数

アロー関数が適している場合:

  • 短い処理の関数

  • 一時的に使う関数

  • 配列のメソッド(後で学習)で使う関数

  • コールバック関数(後で学習)

今の段階では:

  • どちらを使ってもOK

  • 慣れるまではfunction宣言でもOK

  • アロー関数の省略記法は、慣れてから使えば十分


演習3-07:アロー関数で偶数判定

演習3-04で作った偶数判定関数を、アロー関数で書き直してみましょう。

解答例:

function myFunction3_07() {
  const isEven = x => x % 2 === 0;
  
  console.log(isEven(4));   // true
  console.log(isEven(5));   // false
}

たった1行で書けました!


第2部:配列 - 複数のデータをまとめて扱う

さて、ここからは「配列」について学びます。

配列とは?

配列とは、**複数のデータをまとめて管理する「箱」**です。

料理で例えるなら:

  • 変数:1つの材料を入れる袋(例:りんご1個)

  • 配列:買い物リスト(例:りんご、バナナ、オレンジ...)

なぜ配列が必要?

こんな状況を想像してください:

// 悪い例:メンバーを別々の変数で管理
const member1 = 'Bob';
const member2 = 'Tom';
const member3 = 'Ivy';
const member4 = 'Jay';
// メンバーが100人いたら...?

配列を使えば:

// 良い例:配列でまとめて管理
const members = ['Bob', 'Tom', 'Ivy', 'Jay'];

配列の3つのメリット:

  1. まとめて管理:関連するデータを一つにまとめられる

  2. ループで処理:for文で全要素を簡単に処理できる

  3. 動的に追加・削除:後から要素を増やしたり減らしたりできる


配列の基本

配列リテラル

構文:

[値1, 値2, 値3, ...]

例:

[10, 30, 20, 40]
['Bob', 'Tom', 'Ivy']
[true, false, true]

配列の代入と参照

配列を変数に代入:

const numbers = [10, 30, 20, 40];

配列の要素を参照:

配列名[インデックス]

重要:インデックスは0から始まる!

配列:  [10,  30,  20,  40]
       ↓    ↓    ↓    ↓
インデックス:0    1    2    3

実際に試してみよう(演習3-08):

function myFunction3_08() {
  const members = ['Bob', 'Tom', 'Ivy'];
  
  console.log(members[0]);  // Bob
  console.log(members[1]);  // Tom
  console.log(members[2]);  // Ivy
  console.log(members);     // [ 'Bob', 'Tom', 'Ivy' ]
  
  // 配列の要素を変更
  members[1] = 'Tim';
  console.log(members);     // [ 'Bob', 'Tim', 'Ivy' ]
}

「あれ?constなのに変更できるの?」

はい、できます。なぜなら:

  • constは「再代入を禁止」

  • 配列の中身を変更することは「再代入」ではない

const members = ['Bob', 'Tom', 'Ivy'];
members[1] = 'Tim';  // OK(配列の中身を変更)
members = ['Alice']; // エラー!(再代入は禁止)

lengthプロパティ:配列の要素数を取得

構文:

配列.length

実際に試してみよう(演習3-09):

function myFunction3_09() {
  const members = ['Bob', 'Tom', 'Jay', 'Tim'];
  console.log(members.length);  // 4
}

lengthとインデックスの関係:

配列:  ['Bob', 'Tom', 'Jay', 'Tim']
インデックス:  0      1      2      3
length: 4

最大のインデックス = length - 1

これは後でループを書くときに重要になります。


配列のループ処理

配列の全要素を処理したいとき、ループを使います。2つの方法があります。

方法1:for文を使う

構文:

for (let i = 0; i < 配列.length; i++) {
  console.log(配列[i]);
}

なぜi < 配列.length?

  • インデックスは0から始まる

  • 最後のインデックスはlength - 1

  • だからi < length(lengthより小さい)でループ

方法2:for...of文を使う

構文:

for (const 定数 of 配列) {
  console.log(定数);
}

for...of文の特徴:

  • インデックスを意識しなくていい

  • 要素を直接取り出せる

  • コードがシンプル

実際に試してみよう(演習3-10):

function myFunction3_10() {
  const members = ['Bob', 'Tom', 'Jay', 'Tim'];
  
  // for文
  for (let i = 0; i < members.length; i++) {
    console.log(members[i]);
  }
  
  // for...of文
  for (const member of members) {
    console.log(member);
  }
}

どちらも同じ結果:

Bob
Tom
Jay
Tim

どっちを使う?

  • インデックスが必要な場合 → for文

  • 要素だけ必要な場合 → for...of文

for...of文がおすすめな理由:

  • コードが短い

  • 読みやすい

  • インデックスのミスが起きない


演習3-11:逆順に出力

以下の配列を、インデックスが大きい順(逆順)にログ出力するスクリプトを作成してみましょう。

['Bob', 'Tom', 'Jay', 'Tim']

解答例:

function myFunction3_11() {
  const members = ['Bob', 'Tom', 'Jay', 'Tim'];
  
  // 逆順にループ
  for (let i = members.length - 1; i >= 0; i--) {
    console.log(members[i]);
  }
}

結果:

Tim
Jay
Tom
Bob

ポイント:

  • 開始値:members.length - 1(最後のインデックス)

  • 条件式:i >= 0(0以上の間)

  • 増減式:i--(1ずつ減らす)


第3部:二次元配列 - 表形式のデータを扱う

ここからは応用編です。二次元配列について学びます。

二次元配列とは?

二次元配列とは、配列の中に配列が入っている構造です。

[
  [10, 30, 20, 40],
  [11, 31, 21],
  [12]
]

イメージ:

[[10, 30, 20, 40],  ← 0番目の配列
 [11, 31, 21],      ← 1番目の配列
 [12]]              ← 2番目の配列

なぜ二次元配列が必要?

実は、GASで二次元配列はとってもよく使います

  • スプレッドシート:セル範囲(行×列)

  • Gmail:スレッド × メッセージ

  • カレンダー:日付 × イベント

スプレッドシートの例:

     A列   B列   C列   D列
1行  10    30    20    40
2行  11    31    21
3行  12

これをGASで取得すると:

[[10, 30, 20, 40], [11, 31, 21], [12]]

二次元配列の要素の参照

基本:

const numbers = [[10, 30, 20, 40], [11, 31, 21], [12]];

console.log(numbers[0]);     // [10, 30, 20, 40](0番目の配列)
console.log(numbers[1]);     // [11, 31, 21](1番目の配列)
console.log(numbers[2]);     // [12](2番目の配列)

さらに深く:

console.log(numbers[0][0]);  // 10(0番目の配列の0番目)
console.log(numbers[0][1]);  // 30(0番目の配列の1番目)
console.log(numbers[0][2]);  // 20(0番目の配列の2番目)
console.log(numbers[0][3]);  // 40(0番目の配列の3番目)

イメージ:

numbers → [[10, 30, 20, 40], [11, 31, 21], [12]]
           ↓
numbers[0] → [10, 30, 20, 40]
              ↓
numbers[0][0] → 10

実際に試してみよう(演習3-12):

function myFunction3_12() {
  const numbers = [[10, 30, 20, 40], [11, 31, 21], [12]];
  
  console.log(numbers[0][0]);  // 10
  console.log(numbers[0][1]);  // 30
  console.log(numbers[0][2]);  // 20
  console.log(numbers[0][3]);  // 40
  console.log(numbers[0]);     // [10, 30, 20, 40]
  console.log(numbers[1]);     // [11, 31, 21]
  console.log(numbers[2]);     // [12]
  console.log(numbers);        // 全体
}

二次元配列のループ処理

二次元配列の全要素を処理するには、ループのネスト(入れ子構造)を使います。

for文のネスト:

for (let i = 0; i < 配列.length; i++) {
  for (let j = 0; j < 配列[i].length; j++) {
    console.log(配列[i][j]);
  }
}

for...of文のネスト:

for (const 行 of 配列) {
  for (const 要素 of 行) {
    console.log(要素);
  }
}

演習3-13:二次元配列の全要素を出力

以下の二次元配列の全要素を出力するスクリプトを作成してみましょう。

[[10, 30, 20, 40], [11, 31, 21], [12]]

解答例1:for文のネスト

function myFunction3_13_v1() {
  const numbers = [[10, 30, 20, 40], [11, 31, 21], [12]];
  
  for (let i = 0; i < numbers.length; i++) {
    for (let j = 0; j < numbers[i].length; j++) {
      console.log(numbers[i][j]);
    }
  }
}

解答例2:for...of文のネスト

function myFunction3_13_v2() {
  const numbers = [[10, 30, 20, 40], [11, 31, 21], [12]];
  
  for (const row of numbers) {
    for (const num of row) {
      console.log(num);
    }
  }
}

どちらも同じ結果:

10
30
20
40
11
31
21
12

for...of文の方が読みやすい!

  • row(行)という名前で、何を処理しているかわかる

  • インデックスのミスが起きない


第4部:関数と配列を組み合わせる

さて、ここまで学んだ「関数」と「配列」を組み合わせてみましょう。

演習3-14:配列の要素数を返す関数

配列を引数として受け取り、その要素数を戻り値として返す関数lenArrayを作成してみましょう。

解答例:

function myFunction3_14() {
  const members1 = ['Bob', 'Tom', 'Jay'];
  console.log(lenArray(members1));  // 3
  
  const members2 = [['Bob', 'Tom', 'Jay']];
  console.log(lenArray(members2));  // 1
}

function lenArray(arr) {
  return arr.length;
}

アロー関数で書くと:

const lenArray = arr => arr.length;

たった1行!

ポイント:

  • members1は配列(要素数3)

  • members2は二次元配列(外側の配列の要素数は1)

  • 関数は引数として配列を受け取れる


まとめ:今日学んだこと

第1部:関数

  • 関数は処理をまとめて名前を付けたもの

  • 引数で値を渡し、戻り値で値を受け取る

  • アロー関数で簡潔に書ける

  • 関数を変数・定数に代入できる

第2部:配列

  • 配列は複数のデータをまとめて管理する

  • インデックスは0から始まる

  • lengthプロパティで要素数を取得

  • for文またはfor...of文でループ処理

第3部:二次元配列

  • 配列の中に配列が入っている構造

  • スプレッドシートのセル範囲は二次元配列

  • ループのネストで全要素を処理

第4部:関数と配列の組み合わせ

  • 関数の引数に配列を渡せる

  • 関数の戻り値として配列を返せる


発展:将来できるようになること

今日学んだ知識を使うと、こんなことができるようになります:

実務自動化の例

1. スプレッドシートのデータ処理

// スプレッドシートから全データを取得(二次元配列)
const data = [
  ['名前', '年齢', '部署'],
  ['Taro', 25, '営業'],
  ['Hanako', 30, '開発'],
  ['Jiro', 28, '営業']
];

// 営業部のメンバーだけ抽出する関数
const filterSales = (data) => {
  const result = [];
  for (const row of data) {
    if (row[2] === '営業') {
      result.push(row);
    }
  }
  return result;
};

const salesMembers = filterSales(data);
// 結果: [['Taro', 25, '営業'], ['Jiro', 28, '営業']]

2. メールアドレスリストの作成

// メンバーリストからメールアドレスを生成する関数
const createEmailList = (members) => {
  const emails = [];
  for (const member of members) {
    emails.push(member + '@company.com');
  }
  return emails;
};

const members = ['taro', 'hanako', 'jiro'];
const emailList = createEmailList(members);
// 結果: ['taro@company.com', 'hanako@company.com', 'jiro@company.com']

// 一括メール送信に使える!

3. データの集計

// 売上データの合計を計算する関数
const calcTotal = (sales) => {
  let total = 0;
  for (const amount of sales) {
    total += amount;
  }
  return total;
};

const monthlySales = [100000, 150000, 120000, 180000];
const totalSales = calcTotal(monthlySales);
// 結果: 550000

今は難しく感じてもOK!
これらの例は、まだ習っていない知識も含まれています。でも、今日学んだ「関数」と「配列」が核になっているんです。

次回以降、「オブジェクト」「スプレッドシート操作」を学んだとき、「あ、あのときの関数と配列がここで使えるんだ!」と気づく瞬間が来ます。


学習のコツ

1. 手を動かす
記事を読むだけでなく、必ず自分でコードを書いて実行してみてください。特に配列のインデックスは、実際に触らないと感覚がつかめません。

2. エラーを楽しむ
「インデックスが範囲外」「関数が定義されていない」といったエラーは、よくあることです。エラーメッセージを読んで、何が間違っているか考えてみましょう。

3. 小さく試す
いきなり複雑な二次元配列を扱おうとせず、まずは単純な配列から。いきなり複雑な関数を書こうとせず、まずはシンプルな関数から。

4. 実務で使ってみる
「この作業、配列で管理したら楽になるかも」「この処理、関数にまとめられるかも」と考えながら、実務で使ってみましょう。

5. アロー関数は焦らない
アロー関数の省略記法は、最初は無理に使わなくてOK。function宣言で十分です。慣れてきたら、少しずつ使ってみましょう。


次回予告

次回は「オブジェクト」について学びます。

  • オブジェクト:データと処理をまとめて管理する仕組み

  • プロパティとメソッド:オブジェクトの中身

  • オブジェクトの配列:実務で最もよく使うデータ構造

配列は「インデックス」でデータを管理しましたが、オブジェクトは「名前」でデータを管理します。

例えば:

// 配列
const member = ['Taro', 25, '営業'];
console.log(member[0]);  // Taro(0って何?)

// オブジェクト
const member = {name: 'Taro', age: 25, dept: '営業'};
console.log(member.name);  // Taro(nameだからわかりやすい!)

オブジェクトを使うと、コードがもっと読みやすくなります。楽しみにしていてください!


最後に

関数と配列、お疲れさまでした!

今回は、プログラミング学習の「山場」の一つです。「ちょっと難しかったかも...」と感じた人も多いかもしれません。

でも、大丈夫。今日学んだことは、何度も使っているうちに自然と身につきます。

関数は、今後あなたが書くすべてのプログラムで使います。
配列は、スプレッドシートを扱う時に必ず使います。

今は完璧に理解できなくても、「こういうものがあるんだな」と覚えておいてください。実務で使うときに、「あ、あれか!」と思い出せれば十分です。

次回の「オブジェクト」を学べば、GASでできることが一気に広がります。あと一息、一緒に頑張りましょう!


ハッシュタグ:#ノンプロ研 #GAS初心者講座

質問や感想は、ノンプロ研のSlackやXでシェアしてくださいね!

いいなと思ったら応援しよう!