GASでプログラミング入門 ～応用編 Vol.1～

社内サークルにてエンジニアから非エンジニアの方向けにプログラミングを教えるという活動を行っています。

今回はその教材応用編の第1弾です。

今まではGASというよりもJavaScriptの基礎文法とアルゴリズムの組み立て方の基礎を学んできたので、本記事以降ではGASを活用した応用編に入っていきたいと思います。

JavaScriptについてある程度知見のある方は本記事から読んでいただいて大丈夫ですが、もしプログラミングに入門して基礎固めをしたいという方がいましたら、下記にVol.1～10までのリンクとそれぞれの記事に含まれる内容を表にしましたので、参考にしていただけますと幸いです。

| 記事 | 内容 |
| ---- | ---- |
| [GASでプログラミング入門 Vol.1](https://qiita.com/YoshinagaYuta/items/7dfef1ef9fdf0e3d2f28) | 変数 |
| [GASでプログラミング入門 Vol.2](https://qiita.com/YoshinagaYuta/items/83f1709bee0a5ef10626) | 逐次・反復・分岐 |
| [GASでプログラミング入門 Vol.3](https://qiita.com/YoshinagaYuta/items/ef2779594c5a101e5dea) | 各種演算子 |
| [GASでプログラミング入門 Vol.4](https://qiita.com/YoshinagaYuta/items/05ed55663786218ad72a) | 関数 |
| [GASでプログラミング入門 Vol.5](https://qiita.com/YoshinagaYuta/items/f2601cffc1aa1498557e) | 関数の戻り値・コメント |
| [GASでプログラミング入門 Vol.6](https://qiita.com/YoshinagaYuta/items/c3cf64078edcd0df5fd7) | let・var・const |
| [GASでプログラミング入門 Vol.7](https://qiita.com/YoshinagaYuta/items/269d051f28d42bd7d979) | 配列 |
| [GASでプログラミング入門 Vol.8](https://qiita.com/YoshinagaYuta/items/c3a547ce6b49a8ae826f) | 連想配列 |
| [GASでプログラミング入門 Vol.9](https://qiita.com/YoshinagaYuta/items/6a2001cd33d46c323021) | null・break・論理演算子 |
| [GASでプログラミング入門 Vol.10](https://qiita.com/YoshinagaYuta/items/fd1d3892c49cfb520bd3) | switch・代入演算子 |

## 前回の演習問題の解答例

(1). 下記のような出力になるプログラムを作成して下さい。
なお、閏年の日数は考慮しないものとします。
※switch文を上手く活用しましょう。

```
 1月の日数は31日です。
 2月の日数は28日です。
 3月の日数は31日です。
 4月の日数は30日です。
 5月の日数は31日です。
 6月の日数は30日です。
 7月の日数は31日です。
 8月の日数は31日です。
 9月の日数は30日です。
10月の日数は31日です。
11月の日数は30日です。
12月の日数は31日です。
```

解答例コード

```js
function myFunction() {
    for (let month = 1; month <= 12; month++) {
        let day = 0;
        switch (month) {
            case 1:
            case 3:
            case 5:
            case 7:
            case 8:
            case 10:
            case 12:
                day = 31;
                break;
            case 2:
                day = 28;
                break;
            case 4:
            case 6:
            case 9:
            case 11:
                day = 30;
                break;
        }
        console.log(month + "月の日数は" + day + "日です。");
    }
}
```

(2). 下記のような出力になるプログラムを作成して下さい。

```
1〜12月の合計日数は365日です。
1〜12月の平均日数は30.416666666666668日です。
```

解答例コード

```js
function myFunction() {
    let total = 0;
    for (let month = 1; month <= 12; month++) {
        let day = 0;
        switch (month) {
            case 1:
            case 3:
            case 5:
            case 7:
            case 8:
            case 10:
            case 12:
                day = 31;
                break;
            case 2:
                day = 28;
                break;
            case 4:
            case 6:
            case 9:
            case 11:
                day = 30;
                break;
        }
        total += day;
    }
    console.log("1〜12月の合計日数は" + total + "日です。");
    console.log("1〜12月の平均日数は" + (total / 12) + "日です。");
}
```

なお解答例はあくまで例なので、必ずしも上記のようになっていないといけないわけではありません。

## スプレッドシートのセルをGASから読み込む

スプレッドシートのセルをGASから読み込むには下記の手順が必要になります。

1. 読み込む対象のスプレッドシートを取得する。
1. 読み込む対象のスプレッドシート内のシートを取得する。
1. 読み込む対象のセルを取得する。

### 現在開いているスプレッドシート内のシートを取得する場合

上記の1～2で、現在GASのコードを書いているスプレッドシート内の開いているシートを取得するコードはこんな感じになります。

```js
// 読み込む対象のスプレッドシートを取得する。(現在開いているスプレッドシート)
const spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
// 読み込む対象のスプレッドシート内のシートを取得する。(現在開いているスプレッドシート内のシート)
const sheet = spreadsheet.getActiveSheet();
```

### 外部のスプレッドシートを指定する場合

#### スプレッドシートのID指定

スプレッドシートURLの`/d/xxxxxxxxx/edit`の`xxxxxxxxx`がIDになりますので、こちらを指定して、外部のスプレッドシートを開くことも可能です。

```js
// 読み込む対象のスプレッドシートを取得する。
const spreadsheet = SpreadsheetApp.openById('xxxxxxxxx');
```

#### スプレッドシートのURL指定

```js
// 読み込む対象のスプレッドシートを取得する。
const spreadsheet = SpreadsheetApp.openByUrl('https://docs.google.com/spreadsheets/d/xxxxxxxxx/edit');
```

### スプレッドシート内のシートを指定する場合

#### シート名で指定する場合

```js
// 読み込む対象のスプレッドシートを取得する。(現在開いているスプレッドシート)
const spreadsheet = SpreadsheetApp.getActiveSpreadsheet();// 読み込む対象のスプレッドシート内のシートを取得する。
const sheet = spreadsheet.getSheetByName('シート1');
```

#### シートの並び順の数値で指定する場合

同一スプレッドシート内に含まれる複数シートが配列に格納されているので、シートの並び順に従って、左から右に向かって配列内の数値を指定します。
配列なので、先頭要素は0から始まります。

```js
// 読み込む対象のスプレッドシートを取得する。(現在開いているスプレッドシート)
const spreadsheet = SpreadsheetApp.getActiveSpreadsheet();// 読み込む対象のスプレッドシート内のシートを取得する。
const sheet = spreadsheet.getSheets()[0];
```

### 単一セルの場合

まずはスプレッドシートの単一セルを読み込む手順です。
※以降は基本的に現在開いているスプレッドシート内のセル操作を対象とします。

```js
// 読み込む対象のスプレッドシートを取得する。(現在開いているスプレッドシート)
const spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
// 読み込む対象のスプレッドシート内のシートを取得する。(現在開いているスプレッドシート内のシート)
const sheet = spreadsheet.getActiveSheet();
// 指定するセルの範囲（A1）を取得
const range = sheet.getRange('A1');
// 値を取得
const value = range.getValue();
```

上記の例ではスプレッドシートのA1セルの内容を読み取っています。

### 複数セルの場合

複数セルを読み込む際は、getRange関数に最大で4つの引数を渡します。
それぞれの引数の意味は下記になっています。

| 引数 | 説明 |
| ---- | ---- |
| 第一引数 | 読み込み時に始点にする行番号。先頭行は1から始まる。 |
| 第二引数 | 読み込み時に始点にする列番号。先頭列は1から始まる。 |
| 第三引数 | 読み込む行数。省略可でデフォルトは1。 |
| 第四引数 | 読み込む列数。省略可でデフォルトは1。 |

少々ややこしいのは、多くのプログラミング言語において、配列を扱う際の先頭インデックスは0でしたが、スプレッドシートやExcelなどの表計算アプリケーションでは多くの場合、先頭を1からカウントすることが多いので、ごっちゃにならないように注意が必要です。

#### 複数セルの値を順番に取り出す（2次元配列について）

複数セルの値を順番に取り出すにはgetRange関数の戻り値から`getValues`関数を呼び出して、2次元の配列にアクセスすることで可能になります。
2次元配列というと少し難しく感じるかもしれませんが、基本的にはスプレッドシートの表をそのままプログラムの配列に対応させたものとして、捉えていただくと良いかもしれません。
今までに扱った配列は1次元配列であり、先頭から何番目の要素という形でアクセスしていました。

```js
let nums = [1, 2, 3, 4];
console.log(nums[0]); // 1
console.log(nums[1]); // 2
console.log(nums[2]); // 3
console.log(nums[3]); // 4
```

2次元配列では下記のようになります。

```js
let nums = [[1, 2, 3, 4],[5, 6, 7, 8]];
console.log(nums[0][0]); // 1
console.log(nums[0][1]); // 2
console.log(nums[1][0]); // 5
console.log(nums[1][1]); // 6
```

要素へのインデックスを二つ続けて書くことで碁盤の目のどこにアクセスするか？を決定しています。

つまり、XY座標で表すと、`nums[y][x]`というような形で、Yで行番号をXで列番号を指定することになります。

ここでもまたややこしいのですが、getRange関数に指定する行と列の番号は先頭を1からだったのに対し、取得後のセルの値は配列なので先頭は0からになるという点です。
非常にややこしいですが、混乱しないようにしてください。

#### セルを縦方向に読み込む場合

```js
// 読み込む対象のスプレッドシートを取得する。(現在開いているスプレッドシート)
const spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
// 読み込む対象のスプレッドシート内のシートを取得する。(現在開いているスプレッドシート内のシート)
const sheet = spreadsheet.getActiveSheet();
// 指定するセルの範囲（A1～A3）を取得
const range = sheet.getRange(1, 1, 3, 1);
// 値を取得
const values = range.getValues();
// 値を出力
for (let i = 0; i < values.length; i++) {
    for (let j = 0; j < values[i].length; j++) {
        console.log(values[i][j]);
    }
}
```

終点とする列番号を1にして、終点の行番号は3になっているので、セルを縦方向に読み込みたい場合は上記のような指定を行います。

#### セルを横方向に読み込む場合

```js
// 読み込む対象のスプレッドシートを取得する。(現在開いているスプレッドシート)
const spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
// 読み込む対象のスプレッドシート内のシートを取得する。(現在開いているスプレッドシート内のシート)
const sheet = spreadsheet.getActiveSheet();
// 指定するセルの範囲（A1～C1）を取得
const range = sheet.getRange(1, 1, 1, 3);
// 値を取得
const values = range.getValues();
// 値を出力
for (let i = 0; i < values.length; i++) {
    for (let j = 0; j < values[i].length; j++) {
        console.log(values[i][j]);
    }
}
```

終点とする列番号を3にして、終点の行番号は1になっているので、セルを横方向に読み込みたい場合は上記のような指定を行います。

## 上記プログラムを実行する際の注意点

上記プログラムGASで実行しようとすると、初回実行時には下記のような確認画面が表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/690018/ba8712b9-5255-36da-4238-5c427095eb2e.png)

権限を確認を押し、GASで使用するGoogleアカウントの確認や、GASで実行する権限などの確認画面が表示されるので、それらで適切な権限を設定しないと実行できませんので、ご注意ください。
※個人のGoogleアカウントなら特に問題ないかと思いますが、組織でGoogleアカウントを利用している場合は管理者の方に承認をいただくなどが必要になるかもしれません。

## 演習問題

(1). スプレッドシートのA1セルに氏名、B1セルに出身、C1セルに趣味、D1セルに一言メッセージを入力しておき、入力したセルをGASのコード内で取得して、下記のような自己紹介を表示するプログラムを作成してください。

```
氏名：鈴木一郎
出身：東京都
趣味：ドライブ
一言：GASを頑張ってマスターする！
```

(2). スプレッドシートのA2セルに10、A3セルに5を入力しておき、入力したセルをGASのコード内で取得して、下記のような出力になるようにプログラムを作成してください。

```
計算結果：2
```

## まとめ

いかがでしたでしょうか？
今回はGASからスプレッドシート内のセルを取得することができるようになりましたので、今までと比べると大分業務効率化する為のGAS活用例がぼんやりとはイメージが付いてきたのではないでしょうか？
次回は任意の値をセルに出力する方法を解説する予定ですので、引き続きお付き合いいただけると幸いです。
それではまた次の記事でお会いしましょう！