1 of 440

V8エンジン対応版の資料を公開しましたこれから学ぶ方はこちらで!

↓�https://docs.google.com/presentation/d/1B4av1gPS9xW4XVRqcih6R4Oe5nQabsm3AYO54Y9HDQ0/edit

2 of 440

ノンプログラマ向け

社内GASレクチャー

3 of 440

これは何か?

私(@sakaimo) が社内でおこなった、ノンプログラマ向けのGoogle Apps Script (GAS) のレクチャーの資料です。

営業やバックオフィス業務を行なっているメンバーが、GASが書けるようになったら業務の効率が上がるのでは?書けなくとも「こんなことができるのか」ってわかってもらえたら、そこから効率化のネタが見つかるのでは?との思いではじめました。

4 of 440

資料の中身について

実際のレクチャではこの資料を見ながら、私がホワイトボードに書いて説明したり、ライブコーディングしていくなどの補足要素があってこそ成り立つ部分もあったりします。

ですので、まったくの初学者がこのドキュメントを見たときに説明不足で「え?」ってなる箇所があるかもしれませんが、そゆことでご了承ください。

コメントはこちら(Qiita)の方にお願いします。

5 of 440

事前の宿題

(宿題1)「頭の体操」なので楽しくやってください!

アルゴロジック2

https://home.jeita.or.jp/is/highschool/algo/prm/index2.html

↑これの「順次処理」「繰り返し」「分岐処理」は必須。

(宿題2)何を効率化したいのか?を決めること

卒業課題にもなりますが、現時点で「GASで実現したいこと」を1つ以上挙げておいてください。

業務ではスプレッドシート、Gmail、GoogleDrive...を使うと思うのですが、

「毎回同じ操作してるな」とか「こゆの自動化できないのかな」っていうネタを出しておくこと!

(レクチャ受けておしまい、になりがちなので少しでも(数秒でも)自分の作業をラクにできた!というプログラムを作って、卒業となります)

→受講中に何ができるのかがわかってきて、課題を変えるってのもOKです。

6 of 440

事前宿題

赤枠内を

クリアしておいてください

7 of 440

事前準備

GoogleDriveにレクチャ用の「フォルダ」を作成してください。

その中にスプレッドシートなどを作っていきます。

8 of 440

GASのためのJavascript入門

社内レクチャ

9 of 440

目次①

10 of 440

目次②

11 of 440

はじめに

12 of 440

注意事項

このスライド上にいっぱいコードが出てきます。

各自のPCでもこのスライドを見えるようにしておいてください。

スライドのコードをコピペして実行してもらうこともあります。

レクチャでは下記の3画面を行ったり来たりします。

下記の「1と2」あるいは「2と3」を同時に見えるようにしておくと効率上がります。

  • このスライド
  • スクリプトエディタ(プログラムを書くところ)
  • スプレッドシート

13 of 440

レクチャーの対象者

  • プログラミングしたことない人
  • だけどプログラムできるようになりたい人
  • 業務でGoogleサービス(スプレッドシート, Gmail, フォーム...)を利用している人
  • ↑これらの手作業を自動化したい人
  • ↑これらで実績を作って自分の経歴書に「GoogleAppsScriptによる業務効率化」と書きたい人

14 of 440

プログラムできるようになると何が良いか

  • プログラミングの敷居がすげー下がってきている
  • できてあたり前の時代へ (義務教育になる時代)
  • 自分で解決できることが増える(開発に頼まなくても良い)
  • 自分のスキルアップ。興味関心の枠が広がる
  • エンジニアと話する時に意思の疎通がしやすくなる(プログラムでできそうじゃない?ということがイメージしやすくなる)
  • IT業界の人になった気になれる

15 of 440

このレクチャーの「卒業試験」に合格すると

さらにその先に

上級

  • 他人のGASもメンテナンスできる
  • 自分のチーム、部署の「GAS担当者」になれる
  • 私のアシスタントになれるw

初級

  • GASを使って自分の業務を効率化ができる
  • 困ったときに自分で調べて解決できるようになる
  • 自分で書いたGASをメンテナンス(不具合対応、機能追加)ができる

16 of 440

そう。「卒業試験」あります。

わかったつもり、で終わらせないために。

自分の業務・作業が少しでもラクになるGASを作成する。

課題提出してもらいます。

レクチャーが終わるまでには課題を決めておいてください。

(どんな小さい効率化でもいいです)

17 of 440

今回扱わないもの

  • Webアプリケーションのこと (クライアント、サーバみたいの)
  • データベースのこと (これ、別枠設けたい)
  • ネットワーク、サーバーのこと
  • コード管理 (Gitとか)
  • テスト駆動開発
  • オブジェクト指向プログラミング

18 of 440

GoogleAppsScriptの紹介

19 of 440

GASでできること

  • スプレッドシートの自動集計
  • ドキュメントの翻訳
  • スプレッドシートからPDFで表を作成してドライブに保存
  • カレンダーに登録している今日の予定をメールやslackに通知
  • フォームに回答してくれた人にお礼メールを自動返信
  • スプレッドシートに書かれている住所をマップにプロット

...など (詳細! GoogleAppsScript完全入門 P12により引用)

20 of 440

<社内実例紹介>

21 of 440

ホントはここに社内事例があったのだけれど、いろいろあって公開できないので、別などこかで公開したいと思います。例としては

  • スプレッドシート内での処理
  • Gmailから特定メールの内容をスプレッドシートに書き出す
  • スプレッドシートが更新されたらSlackに通知する

みたいな例です。

22 of 440

(GASに限らず)プログラム...って?

23 of 440

プログラミング言語って何?

コンピュータの中は0と1でできている(らしい)

https://style.nikkei.com/article/DGXKZO97458000Z10C16A2W12001?channel=DF210220171916

そのコンピュータに命令するための(人間がみてわかる)「言語」

機械がわかる

ように変換

人が見て

わかる表現

24 of 440

プログラムのキホン

「順次、分岐、反復」(アルゴロジックでやったやつ)

順次:上から順番に実行される

分岐:「条件」によって処理が変わる

反復:条件が満たされる限り、処理を繰り返す

...例えば右図は「人生フローチャート」

25 of 440

プログラムのキホン

「順次、分岐、反復」

順次:上から順番に実行される

分岐:「条件」によって処理が変わる

反復:条件が満たされる限り、処理を繰り返す

26 of 440

プログラムのキホン

「順次、分岐、反復」

順次:上から順番に実行される

分岐:「条件」によって処理が変わる

反復:条件が満たされる限り、処理を繰り返す

27 of 440

プログラムのキホン

「順次、分岐、反復」

順次:上から順番に実行される

分岐:「条件」によって処理が変わる

反復:条件が満たされる限り、処理を繰り返す

28 of 440

プログラムのキホン

「順次、分岐、反復」

順次:上から順番に実行される

分岐:「条件」によって処理が変わる

反復:条件が満たされる限り、処理を繰り返す

プログラミングは、これらの処理を

「プログラム言語」で表現する

29 of 440

機械は空気を読んでくれない

人間は空気、行間、暗黙の了解、を理解できる。機械はそゆのわからない。

例えば会話で「先週は毎日ランチにラーメン食べたよ」というのは、人間なら「先週の平日のランチがラーメンだったんだな」って解釈する場合もあるだろうけど、機械では「土日祝祭日も含めて先週の7日間のランチがラーメンだった」って解釈するし「先週」っていつ起算の7日間のことかもわからない。

→曖昧さをなくすのが大事

30 of 440

GASを書くデモをします

ライブコーディングするので

私の画面を眺めててください

31 of 440

フォルダ内にスプレッドシートを作成

ツール > スクリプトエディタ

32 of 440

やることは3つ

  • コードを書く
  • 保存する
  • 関数を選ぶ
  • 実行する

1.コードを書く

4.実行する

2.保存する

3.関数を選ぶ

33 of 440

初回だけ認証が必要

34 of 440

スプレッドシートの方に表示されているはず

これで「GASが動いている」ことが

確認できました!

35 of 440

コードの解説

function myFunction() {� Browser.msgBox('hello world');�}

Browser(画面)に、

msgBox(メッセージボックス)を出してね。

表示させるのは「hello world」ね。

という命令

プログラミングとは、機械に命令すること。

36 of 440

では、他にどんな「命令」があるのか

GoogleAppsScrip全体のリファレンスはこちら

https://developers.google.com/apps-script/reference/calendar/

Browserに対する命令

https://developers.google.com/apps-script/reference/base/browser

↑これらの「リファレンス」はよく参照することになります。

37 of 440

GASを書いてみよう

38 of 440

スクリプトエディタを開く

このスプレッドシートに紐づくスクリプトが開く

境野_GASレクチャー

39 of 440

コピペして実行してみよう。

function myFunction() {� var name = Browser.inputBox('Enter your name', Browser.Buttons.OK_CANCEL);� Logger.log(name + 'が入力されました');�}

実行するとinputBoxが

スプレッドシートの方に出る

40 of 440

コピペして実行してみよう。

名前を入力して「OK」を押す

スクリプトエディタに戻って

ログを表示する

41 of 440

入力された文字がログに出力されている

下記を試してみよう。

  • Logger.log(name + 'が入力されました'); ←この赤字部分を変える
  • ダイアログに入力する文字列を変えてみる

42 of 440

何が起こってるか

プログラムが実行されると、

ダイアログが表示される

入力された文字列を

プログラムが受け取る

入力された文字列 + ‘が出力されました’

という形にしてログに出力する

43 of 440

こういう意味です

function myFunction() {� var name = Browser.inputBox('Enter your name', Browser.Buttons.OK_CANCEL);

� Logger.log(name + 'が入力されました');�}

myFunction という名前の「関数=function」です。

44 of 440

こういう意味です

function myFunction() { var name = Browser.inputBox('Enter your name', Browser.Buttons.OK_CANCEL);

� Logger.log(name + 'が入力されました');}

1) この関数はここから始まって

3) ここまでです

2) 赤四角の中が関数の実体で

45 of 440

関数は複数書けます

function myFunctionA() {� Logger.log('ファンクションAです');�}

function myFunctionB() {� Logger.log('ファンクションBです');�}

この場合、myFunctionA と myFunctionB は別の関数です。

myFunctionAを実行しても、Bは実行されません。

46 of 440

さっきのコード解説 (今は「なんとなく」でいい)

function myFunction() {� var name = Browser.inputBox('Enter your name', Browser.Buttons.OK_CANCEL);

� Logger.log(name + 'が入力されました');�}

Browser(画面)に、[テキスト入力ダイアログ(ポップアップ)」を出してね。

メッセージは「Enter your name」にして、

OKボタンとCancelボタンを出してね。

→入力された文字列を受け取る

47 of 440

コード解説 (今はなんとなくでいい)

function myFunction() {� var name = 'Google太郎';

� Logger.log(name + 'が入力されました');�}

つまり、ここ全体が「入力された文字」になる

48 of 440

コード解説 (今はなんとなくでいい)

function myFunction() {� var name = 'Google太郎';

� Logger.log(name + 'が入力されました');�}

受けっとた文字列を、name という 変数 に 代入する

(name の中身が ‘Google太郎’ になる)

49 of 440

コード解説 (今はなんとなくでいい)

function myFunction() {� var name = 'Google太郎';

Logger.log(name + 'が入力されました');�}

name の後ろに ‘が入力されました’ をくっつけて ログに出力する

50 of 440

コード解説 (今はなんとなくでいい)

function myFunction() {� var name = ‘Google太郎’;

Logger.log(name + 'が入力されました');�}

‘Google太郎が入力されました’ ログに出力される

51 of 440

もちょっと実用的なヤツを書いてみよう

スプレッドシートにあるアドレスにメールを送る君

52 of 440

下記のシートを作成してください

「シート1」にこれらを記入してください

53 of 440

スクリプトエディタを開く→下記をコピペする!

function sendMail() {� var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();� var sheet = spreadsheet.getActiveSheet();� var data = sheet.getDataRange().getValues();�� for (var i = 1; i < data.length; i++) {� var to = data[i][0];� var subject = data[i][1];� var body = data[i][2];� GmailApp.sendEmail(to, subject, body);� }�}

54 of 440

実行する★実際にメールが送信されるので宛先には注意ね

1. sendMailを選ぶ

3.成功すればメールが届く

2.実行する

(認証画面が出たら認証する)

55 of 440

何をやったか

56 of 440

コード全体はこれ(今はわからなくていいデス)

57 of 440

大雑把に言うとこうなる

スプレッドシートから情報の「かたまり」を取得する

かたまり=メアドと宛先と本文が入ってる

「かたまり」から1つずつ取り出す

メールを送信する

58 of 440

レクチャー終わったら理解できます

関数

変数

メソッドの呼び出しと戻り値

ループ

配列

引数ありのメソッド呼び出し

59 of 440

大事なこと:エラーは当たり前にでます

エラーはプログラムの間違いを教えてくれます。

うまく付き合っていきましょう!

...など、いっぱい出ます。いやマジで。

くじけないでね。

60 of 440

よくある原因

Typo(タイポ)

打ち間違い。’company’ が ‘conpany’になってたり。

カッコの閉じ忘れ

Logger.log(‘あいうえお’; とか。

文末の;を書き忘れる

「1つの命令はここまでです」というための目印が;です (GASでは)

大文字小文字のミス

Logger.Log(‘あいうえお’); はエラーになる。(正しくは Logger.log )

全角半角ミス

Logger.log(‘あいうえお’); はエラーになる。赤字部分が「全角」だから

61 of 440

Google Apps Scriptとは?

Googleのアプリたちと話ができるプログラム言語、ってこと。

「まったく新しい言語」ではなくJavascript がベース。

レクチャ内で「わからなかったら調べる」アクションが出てきますが、

検索ワードとして「javascript 配列」みたいなワードになるのはこのためです。

Javascript(の一部)をマスターしてもらいます!

62 of 440

事前準備:この記号、入力できます?

バックスラッシュ

Win :「¥」あるいは「ろ」�Mac:「option + ¥」

パイプ

shift+¥

すべて「半角」で!

全角だとエラーになります。

63 of 440

GASのキホン

64 of 440

GAS使いになるためにマスターしてほしいこと

  • 変数…箱と中身
  • 算術演算子…数字の計算ができる
  • 文字列結合…文字列をくっつける
  • Javascriptのルール…コーディングする上でのルール
  • 条件分岐…もし●●だったら☓☓をする
  • 配列…大きな箱に複数の箱を入れられる
  • ループ…処理の繰り返し
  • 関数…処理をひとまとめにしておく
  • 組み込み関数…始めから用意されている「道具」

65 of 440

変数

  • 変数…箱と中身
  • 算術演算子…数字の計算ができる
  • 文字列結合…文字列をくっつける
  • Javascriptのルール…コーディングする上でのルール
  • 条件分岐…もし●●だったら☓☓をする
  • 配列…大きな箱に複数の箱を入れられる
  • ループ…処理の繰り返し
  • 関数…処理をひとまとめにしておく
  • 組み込みオブジェクト…始めから用意されている「道具」

66 of 440

変数は箱。箱に値を入れられる。

function variable1() {� var num;� num = 10;� Logger.log(num);�}

1.スクリプトエディタに書く

2.保存する

3.実行する

4.ログを見る

sendMail() の下にコピペして variable1 を実行してください

67 of 440

ログの見方

■見方1

メニュー>表示>ログ

■見方2(ショートカット)

Win: Ctrl+Enter

Mac: Cmd+Enter

ログって何?

プログラムの実行時の情報をテキストで出力したもの。

変数の中身や、どこまでプログラムが来ているかを確認したりできる。

あるいはプログラムの動作を「ログファイル」に記録しておくことで、後から実行記録として動作確認の手がかりにしたりする。

68 of 440

変数は箱。箱に値を入れられる。

function variable1() {� var num; ①� num = 10; ②� Logger.log(num); ③�}

num

①numという名前の箱を用意する

num

②numに10を

「代入」する

10

③num(の中身)を

ログに出力する

69 of 440

変数は上書きできる

function variable1() {� var num;� num = 10;� Logger.log(num);�

num = 20;� Logger.log(num);�}

70 of 440

変数は複数書ける

function variable2() {� var kokugo;� var sansu;� var eigo;� var total;� � kokugo = 80;� sansu = 100;� eigo = 60;�� total = kokugo + sansu + eigo;� � Logger.log(total);�}

何をしているか

説明してみよう

71 of 440

変数で足し算できる

function variable2() {� var kokugo;� var sansu;� var eigo;� var total;� � kokugo = 80;� sansu = 100;� eigo = 60;�� total = kokugo + sansu + eigo;� � Logger.log(total);�}

変数で足し算(計算)できます

72 of 440

「コメント」は実行されない

function variable2() {

/*

変数の宣言と

変数への代入

*/� var kokugo;� var sansu;� var eigo;� var total;�� kokugo = 80;� sansu = 100;� eigo = 60;�

// 合計を計算して出力� total = kokugo + sansu + eigo;� Logger.log(total);�}

コメントの使いみち

やってることの説明などを書く。

上級者になると「プログラム自体をみればやってることはわかるので、コメントを書いておくと両方メンテナンスする必要があるので、そゆコメントは少ない方がいい」になる

複数行のコメント

/* から始まって

*/ で終わる中はコメントになる

1行コメント

// の後がコメントになる

73 of 440

算術演算子

  • 変数…箱と中身
  • 算術演算子…数字の計算ができる
  • 文字列結合…文字列をくっつける
  • Javascriptのルール…コーディングする上でのルール
  • 条件分岐…もし●●だったら☓☓をする
  • 配列…大きな箱に複数の箱を入れられる
  • ループ…処理の繰り返し
  • 関数…処理をひとまとめにしておく
  • 組み込みオブジェクト…始めから用意されている「道具」

74 of 440

どういうことができるの?の調べ方

[Javascript 算術演算子] で検索してみてください!

下記の5つについて調べてください。(すべて半角記号)

+ (プラス=たす)

- (マイナス=ひく)

* (アスタリスク=かける)

/ (スラッシュ=わる)

% (パーセント=あまり)

75 of 440

問題:3科目の平均を出力してください

function average3Test() {� var kokugo = 80;� var sansu = 100;� var eigo = 60;� var average;���

Logger.log(average);�}

変数の「宣言」と同時に「代入」もできる

ここに自由に書いてください

3教科の平均点が出力されたらOK

76 of 440

回答案:averageに計算結果を入れる

function average3Test() {� var kokugo = 80;� var sansu = 100;� var eigo = 60;� var average;�� average = (kokugo + sansu + eigo) / 3;� Logger.log(average);�}

averageという変数を宣言し、

その中に平均値を代入して

averageを出力する

出力結果

整数をログに出す時に小数点1位まで出力されるのはGASのログの仕様なので気にしない!

77 of 440

回答案:averageを使わなくてもイケル

function average3Test() {� var kokugo = 80;� var sansu = 100;� var eigo = 60;�� Logger.log((kokugo + sansu + eigo) / 3);�}

averageという変数にいれず、

直接計算結果を出力も可能。

averageという変数に入れることで、その値が「何を意味しているのか」がわかりやすくなるので、私はaverageを用意したい派

78 of 440

文字列結合

  • 変数…箱と中身
  • 算術演算子…数字の計算ができる
  • 文字列結合…文字列をくっつける
  • Javascriptのルール…コーディングする上でのルール
  • 条件分岐…もし●●だったら☓☓をする
  • 配列…大きな箱に複数の箱を入れられる
  • ループ…処理の繰り返し
  • 関数…処理をひとまとめにしておく
  • 組み込みオブジェクト…始めから用意されている「道具」

79 of 440

文字列結合の実験

function stringTest() {� var firstName = '太郎';� var lastName = 'Google';� � // 文字列を結合する� Logger.log('こんにちは ' + lastName + firstName + ' さん');�� // 改行は \n で表現できる� Logger.log('今日はとても\nいい天気ですね!');�}

文字列は + で繋げられる

変数には文字列も入れられる

バックスラッシュ

Win :「¥」あるいは「ろ」�Mac:「option + ¥」

80 of 440

文字列のこと

  • 文字列はシングル or ダブルクォーテーションでくくる
  • どっちでも動きます!!
  • ダブルクォーテーションの中でダブルクォーテーションを表示したいときはバックスラッシュで「エスケープ」する

コード: Logger.log(“最近は\”スプラトゥーン2\”がマイブームです。”);

出力: 最近は”スプラトゥーン2”がマイブームです。

81 of 440

Javascriptのルール

  • 変数…箱と中身
  • 算術演算子…数字の計算ができる
  • 文字列結合…文字列をくっつける
  • Javascriptのルール…コーディングする上でのルール
  • 条件分岐…もし●●だったら☓☓をする
  • 配列…大きな箱に複数の箱を入れられる
  • ループ…処理の繰り返し
  • 関数…処理をひとまとめにしておく
  • 組み込みオブジェクト…始めから用意されている「道具」

82 of 440

初めての人が困るところ(と私が思うところ)

どこが「決められた」部分で、

どこが「好きにしていい」部分なのかわからない。

例えば改行とか、スペースとか、大文字小文字は区別するのかとか。

この記号は必要なのかなくてもいいのか、とか。。。

83 of 440

2種類の「決まりごと」があります。

  • 言語として決まっている部分
    • これを間違うとエラーになってプログラムが実行できない
    • プログラムの世界では守らなければ生きていけないもの
    • エラー=プログラムが「ルール違反だよ」って教えてくれる

  • プログラムを書く人の中でのマナー
    • 例えば1つのGoogleスライドを複数人で作るときを想像してください
      • 見出しのフォントサイズは?基調にする色は?
      • 語尾は「ですます」「だである」どっち?
      • 画像の引用の表示方法は?...みたいなルールがあったほうがいいよね。
    • 守らなくてもプログラムは動作する
    • 「動作はするけど読みにくい、統一感が無い」みたいなことになる

84 of 440

言語として決まっていること

プログラムは「半角英数記号」で書く

どこがおかしいでしょうか?

85 of 440

言語として決まっていること

プログラムは「半角英数記号」で書く

ここが「全角」になってる

86 of 440

決まっていること「javascript 予約語」(ググってみる)

  • 変数、関数、メソッド、あるいはオブジェクトの識別子として用いることはできません。

function myFunction() {� var new = "あたらしい";� Logger.log(var new);�}

newは予約語なので

このまま実行すると

エラー

87 of 440

スクリプトエディタが予約語を教えてくれる

青色 = 変数宣言

紫色 = 予約語

水色 = 宣言済の変数

88 of 440

書く人のマナー(コーディングルール)

例えば...

  • 変数名やクラス名の付け方
    • スネークケース: admin_user_name
    • キャメルケース: adminUserName
  • インデントは半角スペース2つにする...など。自分たちで決める。
  • Googleが採用しているルール

89 of 440

見やすくするマナー

function myFunction(){var kokugo=80;var sansu=100;var eigo=60;var total;Logger.log((kokugo+sansu+eigo)/3);}

全部を1行で書いても動くけれど、わかりにくい!

イコールを縦に揃えることで

パッとみてわかる

インデントすることで

どこまでがmyFunctionの中

なのか視認しやすくなる

JSではインデントは

半角スペース2個がルール

ここに半角スペースがあることで視認性が上がる

ここに半角スペースがあることで視認性が上がる

ここに半角スペースがあることで視認性が上がる

90 of 440

今までのファイルを保存してこの章を完了します

名前を

「基本的なこと」

にしてください

91 of 440

条件分岐

  • 変数…箱と中身
  • 算術演算子…数字の計算ができる
  • 文字列結合…文字列をくっつける
  • Javascriptのルール…コーディングする上でのルール
  • 条件分岐…もし●●だったら☓☓をする
  • 配列…大きな箱に複数の箱を入れられる
  • ループ…処理の繰り返し
  • 関数…処理をひとまとめにしておく
  • 組み込みオブジェクト…始めから用意されている「道具」

92 of 440

新しいスクリプトファイルを作成

名前を

「条件分岐」

にしてください

93 of 440

プログラムはフローチャートで表現できる

http://www.edu-ctr.pref.okayama.jp/jyose/kyoiku_shien/jweb/b/b2i1kyouzai3.htm

94 of 440

「もし●●なら」がif文

http://www.edu-ctr.pref.okayama.jp/jyose/kyoiku_shien/jweb/b/b2i1kyouzai3.htm

朝起きる;

�登校の準備をする;

if (雨が降っている) {� 雨具を準備する;�}

�家を出る;�

学校に到着;

95 of 440

「もし●●なら」がif文

http://www.edu-ctr.pref.okayama.jp/jyose/kyoiku_shien/jweb/b/b2i1kyouzai3.htm

朝起きる;

�登校の準備をする;

if (雨が降っている) {� 雨具を準備する;�}

�家を出る;�

学校に到着;

雨が降っているときだけ

実行される処理

96 of 440

if文の「条件式」

if (条件式) {� 条件式がtrueの場合に実行する処理�}

条件式」は 真偽値(true か false) になるもの

(例)

if ( num > 10 ) // numが10より大きければ()の中がtrueになる

if ( str === ‘おはよう’ ) // stgが文字列「おはよう」と一致すればtrue

この記号はあとでやります

97 of 440

ifを書いてみる (「条件分岐」の中にコピペして実行してみてください)

function testIf() {� var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();� var x = Browser.inputBox('数字を入れよう', Browser.Buttons.OK_CANCEL);�� if ( x < 10 ) {� sheet.getRange('A5').setValue(x + 'は10より小さい');� }

}

出力先のセル

ここは自由に設定可能

98 of 440

ifを書いてみる

function testIf() {� var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();� var x = Browser.inputBox('数字を入れよう', Browser.Buttons.OK_CANCEL);�� if ( x < 10 ) {� sheet.getRange('A5').setValue(x + 'は10より小さい');� }

}

ここが実行される

この条件式がtrueの時に

99 of 440

if-else

function testIf() {� var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();� var x = Browser.inputBox('数字を入れよう', Browser.Buttons.OK_CANCEL);�� if ( x < 10 ) {� sheet.getRange('A5').setValue(x + 'は10より小さい'); } else {� sheet.getRange('A5').setValue(x + 'は10以上');� }�}

条件式が true の時に

実行される処理

条件式が false の時に

実行される処理

100 of 440

if...else if

function testIf() {� var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();� var x = Browser.inputBox('数字を入れよう', Browser.Buttons.OK_CANCEL);�� if ( x < 10 ) {� sheet.getRange('A5').setValue(x + 'は10より小さい');� } else if ( x < 20 ) {� sheet.getRange('A5').setValue(x + 'が20より小さい');� } else {� sheet.getRange('A5').setValue(x + 'は20以上');� }�}

条件式を増やせる

101 of 440

if文での注意点

function testIf() {� var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();� var x = Browser.inputBox('数字を入れよう', Browser.Buttons.OK_CANCEL);� if ( x < 10 ) {� sheet.getRange('A5').setValue(x + 'は10より小さい');� } else if (x < 20 ) {� sheet.getRange('A5').setValue(x + 'が20より小さい');� } else {� sheet.getRange('A5').setValue(x + 'は20以上');� }

// 次はここにくる�}

(2)この中に入ったら

(3)ここには入らないし

(4)elseにも入らないで

(5)ifを抜けます

(1)ここからifが始まって

102 of 440

この2つの違いは何でしょう?

function if_2() {� var comment = 'こんにちわ';�� // この書き方と� if (comment === 'おはよう') {� Logger.log('good morning!');� } � if (comment === 'こんにちわ') {� Logger.log('hello!');� }� if (comment === 'こんばんわ') {� Logger.log('good evening!');� }�}

function if_3() {� var comment = 'こんにちわ';� � if (comment === 'おはよう') {� Logger.log('good morning!');

� } else if (comment === 'こんにちわ') {� Logger.log('hello!');

� } else if (comment === 'こんばんわ') {� Logger.log('good evening!');� }�}

出力される結果は同じです。

103 of 440

この2つの違いは何でしょう?

function if_2() {� var comment = 'こんにちわ';�� // この書き方と� if (comment === 'おはよう') {� Logger.log('good morning!');� } � if (comment === 'こんにちわ') {� Logger.log('hello!');� }� if (comment === 'こんばんわ') {� Logger.log('good evening!');� }�}

function if_3() {� var comment = 'こんにちわ';� � if (comment === 'おはよう') {� Logger.log('good morning!');

� } else if (comment === 'こんにちわ') {� Logger.log('hello!');

� } else if (comment === 'こんばんわ') {� Logger.log('good evening!');� }�}

false

true

false

true

ここは通らない

false

104 of 440

なんちゃってボット

function testIf2() {

var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('bot');� var x = Browser.inputBox('なにか入れよう', Browser.Buttons.OK_CANCEL);�� if ( x === 'おはよう' ) {� sheet.getRange('A5').setValue('ぐもーにん!');� } else if ( x === 'こんにちわ' ) {� sheet.getRange("A5").setValue('はろー!!');� } else {� sheet.getRange("A5").setValue('よくわかりません。。。_| ̄|○');� }�}

スプレッドシートに「bot」というシートを追加してください。

else if() を増やしてみよう!

105 of 440

Tips ウィンドウを2つ並べるとやりやすいです

106 of 440

条件式と比較演算子・論理演算子

Javascript 比較演算子

「===」とか「>=」「<=」とか

(「同じかどうか」を比較するときは「==」じゃなくて「===」を使う!)

Javascript 論理演算子

「&&」と「||」と「!」

「かつ」と「または」と反転

// 論理演算子の例

if( (x>=50) && (x<100) ) {� Logger.log('xが50以上かつ100未満です');�}

107 of 440

ここまでのまとめテスト!

108 of 440

たかし君のテストの点数を評価する

たかし君は国語、算数、英語のテストを受けました。

国語は80点、算数が100点、英語は60点でした。

この学校では3教科の平均によって下記のように成績が決まっています

  • 80点以上:優
  • 60点以上80点未満:良
  • 40点以上60点未満:可
  • 40点未満:不可

また、お母さんから「平均点が75点以上だったらお小遣いup」を約束されています。

たかし君の各教科の点数に応じて、

  • 成績
  • お小遣いアップできるか否か

を出力するプログラムを書きなさい。ただし出力は下記のフォーマットとする

今回のたかし君の平均点は●点です。

よって成績は「●(優、良、可、不可のいずれか)」でした。

お小遣いアップ(「できました。」あるいは「できませんでした。」)

109 of 440

この続きを書いてください

function takashi() {� var kokugo = 80;� var sansu = 100;� var eigo = 60;� � /*� ここに処理を書く

出力はLogger.logで� */�}

■3教科の平均によって下記のように成績が決まっています

  • 80点以上:優
  • 60点以上80点未満:良
  • 40点以上60点未満:可
  • 40点未満:不可

■「平均点が75点以上だったらお小遣いup」を約束されています。

成績に応じて、

  • 成績
  • お小遣いアップできるか否か

を出力する。出力は下記のフォーマットとする

----------------------------------------------------------------------

今回のたかし君の平均点は●点です。

よって成績は「●(優、良、可、不可のいずれか)」でした。

お小遣いアップ(「できました。」あるいは「できませんでした。」)

ここの値を色々変えても正しい計算結果になるようにね!

110 of 440

この続きを書いてください (回答案はコメント欄に)

function takashi() {� var kokugo = 80;� var sansu = 100;� var eigo = 60;�

// 必要なモノはこれ

var average; //平均

var grade; //成績

//averageを計算する

//gradeを計算する

//出力する�}

■3教科の平均によって下記のように成績が決まっています

  • 80点以上:優
  • 60点以上80点未満:良
  • 40点以上60点未満:可
  • 40点未満:不可

■「平均点が75点以上だったらお小遣いup」を約束されています。

成績に応じて、

  • 成績
  • お小遣いアップできるか否か

を出力する。出力は下記のフォーマットとする

----------------------------------------------------------------------

今回のたかし君の平均点は●点です。

よって成績は「●(優、良、可、不可のいずれか)」でした。

お小遣いアップ(「できました。」あるいは「できませんでした。」)

ここの値を色々変えても正しい計算結果になるようにね!

111 of 440

ショートカットあります

関数の実行

  • Win: ctrl + R
  • Mac: command + R

ログの表示

  • Win: ctrl + Enter
  • Mac command + Enter

112 of 440

配列

  • 変数…箱と中身
  • 算術演算子…数字の計算ができる
  • 文字列結合…文字列をくっつける
  • Javascriptのルール…コーディングする上でのルール
  • 条件分岐…もし●●だったら☓☓をする
  • 配列…大きな箱に複数の箱を入れられる
  • ループ…処理の繰り返し
  • 関数…処理をひとまとめにしておく
  • 組み込みオブジェクト…始めから用意されている「道具」

113 of 440

新しいスクリプトファイルを作成

名前を

「配列とループ」

にしてください

114 of 440

配列ってなんぞ?

変数は1つの値を格納できる。

var num = 10;

var numbers = [10, 30, 5, 25];

配列は複数の値を格納できる。

num

10

0

1

2

3

10

30

5

25

numbers

115 of 440

用語をおぼえとこう

var numbers = [10, 30, 5, 25];

0

1

2

3

10

30

5

25

numbers

配列名

(自由に決めていい)

要素

(各インデックスの中身)

インデックス

(0から始まる)

116 of 440

書いてみる (fruits配列を作ります)

function myArray() {� var fruits = ['banana', 'orange', 'apple'];� � // 要素を取り出す� Logger.log(fruits[2]);�� // 要素を上書きする� fruits[2] = 'melon';� Logger.log(fruits[2]);� � // 要素を追加する� fruits[3] = 'peach';� Logger.log(fruits); // これで「配列」を出力できる�}

117 of 440

書いてみる

function myArray() {� var fruits = ['banana', 'orange', 'apple'];� � // 要素を取り出す� Logger.log(fruits[2]);�� // 要素を上書きする� fruits[2] = 'melon';� Logger.log(fruits[2]);� � // 要素を追加する� fruits[3] = 'peach';� Logger.log(fruits); // これで「配列」を出力できる�}�

このやり方だと

一番大きいインデックスを知らないと、その次に追加できない。

118 of 440

配列を扱うための「道具」が用意されている

function myArray2() {� var fruits = ['banana', 'orange', 'apple'];� � // 配列の要素数(最大インデックスではない)� Logger.log(fruits.length);� � // 配列の最後に要素を追加する� fruits.push('grape');� Logger.log(fruits);� � // 一致する値のインデックス� Logger.log(fruits.indexOf('orange'));� Logger.log(fruits.indexOf('peach')); // 存在しない場合、何が表示されるか?� }

119 of 440

どんな「道具」があるか調べるには?

「Javascript 配列」とか「Javascript array」で検索!!

(「console.log」が出てきたら「Logger.log」に置き換えること)

いっぱいある。

覚えられない。

覚えなくていい。

何かしようとした時に自分で調べて試せることが大事。

例「Javascript 配列 追加」とかでググれば出てくる!

120 of 440

おみくじサンプル (コピペして実行)

function omikuji() {� var omikuji = ['大吉','中吉', '吉', '凶'];

// omikuji[x] で要素を取り出せる。xを0から3のランダムな整数にしたい。�� var x = Math.floor(Math.random() * 4); //0~3のランダム整数 Logger.log( omikuji[x] );�}

配列の中身の数を変えて試してみよう。

「最大インデックス = 赤字部分の数字」にしよう

121 of 440

おみくじサンプル (コピペして実行)

function omikuji() {� var omikuji = ['大吉','中吉', '吉', '凶'];

// omikuji[x] で要素を取り出せる。xを0から3のランダムな整数にしたい。�� var x = Math.floor(Math.random() * omikuji.length); Logger.log( omikuji[x] );�}

4ってつまり配列の要素数のこと

122 of 440

ループ

  • 変数…箱と中身
  • 算術演算子…数字の計算ができる
  • 文字列結合…文字列をくっつける
  • Javascriptのルール…コーディングする上でのルール
  • 条件分岐…もし●●だったら☓☓をする
  • 配列…大きな箱に複数の箱を入れられる
  • ループ…処理の繰り返し
  • 関数…処理をひとまとめにしておく
  • 組み込みオブジェクト…始めから用意されている「道具」

123 of 440

ループ

「処理の繰り返し」のための構文。

例:1以上10以下の整数を出力するプログラム

124 of 440

ループ

処理の繰り返し」のための構文。forとwhileがあります。

例:1以上10以下の整数を出力するプログラム

<疑問>

これのどこが「繰り返し」なの?

<回答>

数字は毎回変わるけど、

「数字を出力する」という処理は繰り返してる

125 of 440

for文で書いてみる

function loopFor() {� for (var i = 1; i <= 10; i++ ) {� Logger.log(i);� }

}

「配列とループ.gs」 の下の方に書いて実行してみよう!

126 of 440

for文の解説

function loopFor() {� for (var i = 1; i <= 10; i++ ) {� Logger.log(i);� }�}

var i = 1; // カウンタ変数の初期値を決める(iじゃなくてもいいがiが定番)

i <= 10; // この式がtrueになる間だけループが実行される

i++ // i を1増やす (ブロックの最後で実行される)

i++ とは i = i + 1 と同じことです!(自分自身に1を足す)

127 of 440

for文の解説 (詳しく)

function loopFor() {� Logger.log(1);� Logger.log(2);� Logger.log(3);� Logger.log(4);� Logger.log(5);� Logger.log(6);� Logger.log(7);� Logger.log(8);� Logger.log(9);� Logger.log(10);�}

1から10を出力するというのは

つまりこういうこと

128 of 440

for文の解説 (詳しく)

function loopFor() {� Logger.log(1);� Logger.log(2);� Logger.log(3);� Logger.log(4);� Logger.log(5);� Logger.log(6);� Logger.log(7);� Logger.log(8);� Logger.log(9);� Logger.log(10);�}

赤字の部分が、1から10まで1つずつ増えてる

129 of 440

for文の解説 (詳しく)

function loopFor() {�

var i = 1;

Logger.log(i);�

i = 2;

Logger.log(i);

i = 3;

Logger.log(i);

…(繰り返し)

i = 10;

Logger.log(i);�}

i に 1 を入れて出力

i に 2 を入れて出力

i に 3 を入れて出力

i に 10を入れて出力

をしたい

130 of 440

for文の解説 (詳しく)

function loopFor() {�

var i = 1;

Logger.log(i);�

i = 2;

Logger.log(i);

i = 3;

Logger.log(i);

…(繰り返し)

i = 10;

Logger.log(i);�}

i に1を代入して「処理(この場合はLogger.log)」する

i に2を代入して「処理」する

i に3を代入して「処理」する

...

i に10を代入して「処理」する

131 of 440

for文の解説 (詳しく)

function loopFor() {�

var i = 1;

Logger.log(i);�

i = 2;

Logger.log(i);

i = 3;

Logger.log(i);

…(繰り返し)

i = 10;

Logger.log(i);�}

i に1を代入して「処理(この場合はLogger.log)」する

i に2を代入して「処理」する

i に3を代入して「処理」する

...

i に10を代入して「処理」する

つまり、こう言える

iを1から始めて、何か処理する。

iが10になるまで繰り返す。

処理が終わるたびに、iに1を足す

132 of 440

for文の解説 (詳しく)

function loopFor() {�

for (var i=1; i<=10; i++){

Logger.log(i);

}

�}

こう書くとそれが実現できる

iを1から始めて 何か処理する。

iが10になるまで 繰り返す。

処理が終わるたびに iに1を足す

133 of 440

1から10までの「合計」を出力する

function oneTen() {� var total = 0;� � for (var i=1; i<=10; i++) {� total = total + i;� }� � Logger.log('合計は' + total + 'です');�}

134 of 440

ポイントがあります

function oneTen() {� var total = 0;� � for (var i=1; i<=10; i++) {� total = total + i;� }� � Logger.log('合計は' + total + 'です');�}

ポイント1

1つの変数の中身を「更新」していく

ポイント2

自分自身に、「自分自身にiを加えたもの」を代入する

135 of 440

ポイントがあります

function oneTen() {� var total = 0;� � for (var i=1; i<=10; i++) {total = total + i;� }� � Logger.log('合計は' + total + 'です');�}

この式の意味は

右辺の計算結果を、左辺に代入する

136 of 440

1回目のループまでの処理の流れ

function oneTen() {� var total = 0;� � for (var i=1; i<=10; i++) {� total = total + i;� }� � Logger.log('合計は' + total + 'です');�}

1) totalに0が代入される

2) i に 1が代入される

4) 左辺「totalという箱(の中身)」

に代入される

3) 「totalという箱の中身(=0) + 1」

処理の順番は

「右辺の計算結果を、左辺に代入する」

5) 結果としてtotalの中身が1になる

137 of 440

2回目のループは?

function oneTen() {� var total = 0;� � for (var i=1; i<=10; i++) {� total = total + i;� }� � Logger.log('合計は' + total + 'です');�}

1) i に 2が代入される

3) 左辺「totalという箱(の中身)」

に代入される

2) 「totalという箱の中身(=1) + 2」

4) 結果としてtotalの中身が3になる

138 of 440

今度は while で書いてみる

function loopWhile() {� var i = 1;� while (i <= 10) {� Logger.log(i);� i++;� }�}

139 of 440

whileのルール

function loopWhile() {� var i = 1;� while (i <= 10) {� Logger.log(i);� i++;� }�}

whileの後の ( ) 内がtrueだったら

{ } 内が実行される

140 of 440

whileのルール

function loopWhile() {� var i = 1;� while (i <= 10) {� Logger.log(i);� i++;� }�}

今回の条件は「iが10以下ならば」

1回のループが終わるごとに iに1を足す

2回目のループのときには 「i <= 10」のiは2になってる。

141 of 440

whileのルール

function loopWhile() {� var i = 1;� while (i <= 10) {� Logger.log(i);� � }�}

もし「i++;」が無いと、

「i <= 10」は常にtrueになる (iは常に1なので)ので

「無限ループ」になる!(処理が終わらない)

142 of 440

ループの「中断」

1から100までの整数一つずつ順番に7をかけた数を出力するプログラム

→ 100以上の結果は出力しない(プログラムを終了する)ようにしたい

function loopBreak() {�� for ( var i = 1; i <= 100; i++ ) {� Logger.log('結果:' + (i * 7) ); � }

� Logger.log('終了しました'); �}

143 of 440

ループの「中断」: break

function loopBreak2() {� var result;

� for ( var i = 1; i <= 100; i++ ) {� result = i * 7;� � if ( result >= 100 ) {� break;� }� Logger.log('結果:' + result); � }

� Logger.log('終了しました'); �}

100以上の結果は出力しない(プログラムを終了する)ようにしたい

break を通るとループを抜ける

これはループの外なので

ループを抜けた後に実行される

144 of 440

ループの「スキップ」

function loopContinue() {� var result;

� for ( var i = 1; i <= 100; i++ ) {� result = i * 7;� Logger.log('結果:' + result); � }

� Logger.log('終了しました'); �}

(再掲)1から100までの整数一つずつ順番に7をかけた数を出力するプログラム

結果が奇数の時だけ出力したい(偶数は出力しない)

145 of 440

ループの「スキップ」: continue

function loopContinue2() {� var result;

� for ( var i = 1; i <= 100; i++ ) {� result = i * 7;� � if ( result % 2 === 0 ) {� continue;� }� � Logger.log('結果:' + result); � }� Logger.log('終了しました'); �}

結果が偶数(2の倍数)のときは出力しない=奇数だけ出力する

continueを通るとそれ以降の処理を

スキップして次のループに移る

continueを通ったときはこれは実行されない

146 of 440

ループの課題

147 of 440

ループ課題

1から100の整数のうち、奇数だけを足した値を出力する。

1+3+5+7+9….. + 99 = 2500 になるので「2500」が出力されたらOK!

function loopTest() {� var total = 0;

// ヒント:繰り返すにはfor文だね。1から100までだね。

// 奇数かどうか、はif文だね。「奇数」をどうやって判別できるかね。

// Google先生に答えを聞くのはアリです。全然アリ。結果が出ればOK。

Logger.log(total);�}

148 of 440

ループをいつ使うか

149 of 440

配列の中身の処理

var fruits = ['banana', 'orange', 'apple'];�

この配列の中身を1つずつ取り出して処理したい。

例えば下記のような出力をしたい。

bananaが好きです

orangeが好きです

appleが好きです

150 of 440

こういう書き方もできるけど、、、

function forArray() {� var fruits = ['banana', 'orange', 'apple'];� � Logger.log(fruits[0] + 'が好きです');� Logger.log(fruits[1] + 'が好きです');� Logger.log(fruits[2] + 'が好きです');�}

要素を指定して取り出す

151 of 440

こういう書き方もできるけど、、、

function forArray() {� var fruits = ['banana', 'orange', 'apple'];� � Logger.log(fruits[0] + 'が好きです');� Logger.log(fruits[1] + 'が好きです');� Logger.log(fruits[2] + 'が好きです');�}

要素数が増えたら大変!!

152 of 440

for文で配列から要素を取り出す

function forArray() {� var fruits = ['banana', 'orange', 'apple'];� � for ( var i = 0; i < fruits.length; i++ ) {� Logger.log(fruits[i] + 'が好きです');� }�}

fruits.length = fruits配列の長さ

i がインデックスを示す

153 of 440

for文で配列から要素を取り出す

function forArray() {� var fruits = ['banana', 'orange', 'apple'];� � for ( var i = 0; i < fruits.length; i++ ) {� Logger.log(fruits[i] + 'が好きです');� }�}

for文の復習

var i = 0; // カウンタ変数の初期値

i < fruits.length; // この式がtrueになる間だけループが実行される

i++ // i を1増やす

154 of 440

for文で配列から要素を取り出す

function forArray() {� var fruits = ['banana', 'orange', 'apple', 'grape'];� � for ( var i = 0; i < fruits.length; i++ ) {� Logger.log(fruits[i] + 'が好きです');� }�}

配列の要素数が増えても、出力ロジックを変える必要がなくなる。

155 of 440

配列からの取り出し方 その2

156 of 440

forEachを使う

function forEachTest() {� var fruits = ['banana', 'orange', 'apple'];� � fruits.forEach(function(fruit){� Logger.log(f + 'がおいしい');� });�}

157 of 440

forEach解説

function forEachTest() {� var fruits = ['banana', 'orange', 'apple'];� � fruits.forEach(function(fruit){Logger.log(fruit + 'がおいしい');});�}

要素1つずつに対して

functionの処理をしてね

配列から取り出した1つの要素は

fruitっていう変数に入れてね

変数名は自由に決められる

fruitsから1つ取り出すからfruitにした

functionの処理

この配列の

158 of 440

少なくともforで取り出すやり方は覚えておいて!

function forArray() {� var fruits = ['banana', 'orange', 'apple'];� � for ( var i = 0; i < fruits.length; i++ ) {� Logger.log(fruits[i] + 'がおいしい');� }�}

function forEachTest() {� var fruits = ['banana', 'orange', 'apple'];� � fruits.forEach(function(fruit){� Logger.log(fruit + 'がおいしい');� });�}

どちらも

結果は同じ

159 of 440

なぜ配列が大事なのか?

160 of 440

スプレッドシートの情報は「配列」として扱う

この1行を

[‘たかし’, ‘国語’, ’80’]

という配列として扱う

161 of 440

スプレッドシートの情報は「配列」として扱う

これ全部を

[

[‘たかし’, ‘国語’, ‘80’],

[‘たかし’, ‘算数’, ‘100’],

[‘たかし’, ‘英語’, ‘60’],

[‘みゆき’, ‘国語’, ‘70’],

[‘みゆき’, ‘算数’, ‘50’],

[‘みゆき’, ‘英語’, ‘100’],

]

という二次元配列で扱う

162 of 440

二次元配列くわしく(1)

配列の復習。1つの「配列」に複数の「要素」がある

// 書き方

var numbers = [10, 30, 5, 25];

0

1

2

3

10

30

5

25

numbers

配列名

要素の1つに 5 という

数字を格納している

インデックス

163 of 440

二次元配列くわしく(2)

要素には「数字」だけじゃなく「文字列」も入れられる

[‘たかし’, ‘国語’, 80]

0

1

2

‘たかし’

‘国語’

80

164 of 440

二次元配列くわしく(3)

要素には「数字」だけじゃなく「配列」も入れられる

(配列の要素の中に配列が入ってる)

0

1

2

0

1

2

‘たかし’

‘国語’

80

0

1

2

‘たかし’

‘算数’

100

0

1

2

‘たかし’

‘英語

60

(イメージ図)

でっかい配列の各要素に、

ちっちゃい配列が入ってる

165 of 440

二次元配列くわしく(4)

「行」の情報が1つの要素になっている配列ができあがる

0

1

2

0

1

2

‘たかし’

‘国語’

80

0

1

2

‘たかし’

‘算数’

100

0

1

2

‘たかし’

‘英語

60

1行目」の情報

2行目」の情報

3行目」の情報

166 of 440

やってみよう

シートを追加して

シート名を「配列」にする。

↓これをA1から貼り付ける

たかし

国語

80

たかし

算数

100

たかし

英語

60

みゆき

国語

70

みゆき

算数

50

みゆき

英語

100

167 of 440

やってみよう

function seiseki() {� var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('配列');� var seiseki = sheet.getDataRange().getValues();�� Logger.log(seiseki);�}

これがseisekiの中身

二次元配列になってる

今は意味がわからなくてOK。丸写ししてください。

意味は「そのシートにあるデータを全部取ってきて

seisekiという名前の配列に入れる」

168 of 440

ログを整形してみる

[

[たかし, 国語, 80.0],

[たかし, 算数, 100.0],

[たかし, 英語, 60.0],

[みゆき, 国語, 70.0],

[みゆき, 算数, 50.0],

[みゆき, 英語, 100.0]

]

整形

169 of 440

この値を取りたいときにどうするか

[

[たかし, 国語, 80.0],

[たかし, 算数, 100.0],

[たかし, 英語, 60.0],

[みゆき, 国語, 70.0],

[みゆき, 算数, 50.0],

[みゆき, 英語, 100.0]

]

170 of 440

ログを整形してみる

[

[たかし, 国語, 80.0],

[たかし, 算数, 100.0],

[たかし, 英語, 60.0],

[みゆき, 国語, 70.0],

[みゆき, 算数, 50.0],

[みゆき, 英語, 100.0]

]

(1) 配列seiseki

(2)

この1行の情報は

seiseki[1]

(3)

seiseki[1]の3番目の要素なので

seiseki[1][2]

171 of 440

イメージ図

0

1

2

0

1

2

‘たかし’

‘国語’

80

0

1

2

‘たかし’

‘算数’

100

0

1

2

‘たかし’

‘英語

60

1行目」の情報

2行目」の情報

3行目」の情報

seiseki[1][2]

172 of 440

書いてみよう

function seiseki() {� var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();� var seiseki = sheet.getDataRange().getValues();�� Logger.log(seiseki[1][2]);�}�

これでたかしの算数の点数が取り出せる

173 of 440

問題:みゆきの算数の点数を取り出したい

function seiseki() {� var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();� var seiseki = sheet.getDataRange().getValues();�� Logger.log(seiseki[x][x]);�}�

みゆきの算数の点数を

出力するにはどうしたらいいか?

174 of 440

覚え方:[縦][横] の順で 「0起算」でカウント

から

次に横を指定

0

1

2

3

4

5

0

1

2

[4][2]

175 of 440

二次元配列についての補足説明

ここ、つまづきポイントだなと思ったので、説明記事を書いてみました。

GASでスプレッドシートを扱うときの二次元配列の教え方

https://qiita.com/sakaimo/items/d535079b5bee4eed8eb1

176 of 440

配列+ループの課題

177 of 440

配列課題(必須)

たかし君の点数の平均を出力するプログラムを、for文を使って書いてください

function scoreAverage() {� var takashiScore = [80, 100, 60];��

� � Logger.log(xxxxxxx);�}

↓出力結果はこれ

//ここにコードを書いてね

//要素を一つずつ取り出して足す(合計)

//合計から平均を出す

178 of 440

配列課題(ヒント)

function forArray() {� var fruits = ['banana', 'orange', 'apple'];� � for ( var i = 0; i < fruits.length; i++ ) {� Logger.log(fruits[i] + 'が好きです');� }�}

以前出てきた下記のコードがヒントです。

「配列の要素を、ひとつずつ取り出して、取り出した要素に対して処理をする」

179 of 440

課題の解説

180 of 440

配列課題(解説:わたしはこう考えた)

function scoreAverage() {� var takashiScore = [80, 100, 60];�� // 出したい結果は何か?� var total = 0;� var average = 0;� � // ここに「処理」を書いて、totalとaverageを作る。�� � Logger.log(xxxxxxx);�}

totalとaverageを作るのがゴール

(初期値としてゼロを入れとく)

そのための「処理」を考える

181 of 440

配列課題(解説:わたしはこう考えた)

function scoreAverage() {� var takashiScore = [80, 100, 60];�� // 出したい結果は何か?� var total = 0;� var average = 0;� � // まずtotalを作る。�� � Logger.log(xxxxxxx);�}

まず totalを考える。

「配列の中身を全部足したい」

「配列を一つ取り出してtotalに足す」

「その次の要素を取り出してtotalに足す」

...を繰り返すことでできそう。

182 of 440

配列課題(解説:わたしはこう考えた)

function scoreAverage() {� var takashiScore = [80, 100, 60];�� // 出したい結果は何か?� var total = 0;� var average = 0;� � // totalを作る。� for (var i=0; i<takashiScore.length; i++){� total = total + takashiScore[i];� }� � // これで配列の中身の合計がでる� Logger.log(total);�}

183 of 440

配列課題(解説:わたしはこう考えた)

function scoreAverage() {� var takashiScore = [80, 100, 60];�� // 出したい結果は何か?� var total = 0;� var average = 0;� � // totalを作る。� for (var i=0; i<takashiScore.length; i++){� total = total + takashiScore[i];� }� � // これで配列の中身の合計がでる� Logger.log(total);

// averageを作る

average = total / takashiScore.length

Logger.log(average);�}

184 of 440

配列課題(任意)

でんぱ組.inc 問題

function dempaTest() {� // 2011年12月25日までのメンバー(加入順)� var dempagumi = ['古川未鈴', '相沢梨紗', '夢眠ねむ', '成瀬瑛美', '跡部みぅ'];� � // 2011年12月25日に[跡部みぅ]が脱退。[藤咲彩音]と[最上もが]が加入� dempagumi.xxx(...);� dempagumi.xxx(...);�� // 2017年8月6日に[最上もが]が脱退� � // 2017年12月30日に[鹿目凛]と[根本凪]が加入� � // この時点でのメンバーを加入順に1人ずつ出力してください

// (ループをつかうこと)��}

考えてもわからない!

[javascript 配列 追加]

とか

[javascript 配列 削除]

で検索だ!

↓出力結果はこれ

185 of 440

二重ループの課題

「かけ算九九」を出力するプログラム。

出力は右記のようにしてください。

function kuku() {�

�}

9✕9まで

186 of 440

二重ループの課題

ループ1

1から9まで増えていく

187 of 440

二重ループの課題

ループ1

1から9まで増えていく

ループ2

1から9まで増えていく

188 of 440

ループ1

function kukuSample() {� for (var i = 1; i <=9; i++){� Logger.log(i*1);� Logger.log(i*2);� Logger.log(i*3);� Logger.log(i*4);� Logger.log(i*5);� Logger.log(i*6);� Logger.log(i*7);� Logger.log(i*8);� Logger.log(i*9);� }�}

ループ1

ここで1~9のループ

189 of 440

ループ1の中でループ2

function kukuSample() {� for (var i = 1; i <=9; i++){� Logger.log(i*1);� Logger.log(i*2);� Logger.log(i*3);� Logger.log(i*4);� Logger.log(i*5);� Logger.log(i*6);� Logger.log(i*7);� Logger.log(i*8);� Logger.log(i*9);� }�}

ループ2

ここでも1~9

190 of 440

こうなる

function kuku() {� for (var i = 1; i <= 9; i++) {� for (var j = 1; j <= 9; j++ ) {� Logger.log(i + '✕' + j + '=' + i*j);� }� }�}

i じゃなくて j のループ

外側のループ(i)

内側のループ(j)

191 of 440

オブジェクト

192 of 440

新しいスクリプトファイルを作成

名前を

「オブジェクト」

にしてください

193 of 440

オブジェクト

これまでは「変数」と「配列」として値を扱ってきました。

もう一つの形が「オブジェクト」

正確に言うと、「配列は、オブジェクトの一部」だそうです。

194 of 440

配列とオブジェクト

配列インデックスをキーにして値を扱える

オブジェクトプロパティをキーにする

seiseki[0] // ‘たかし’のこと

seiseki[2] // 80のこと

seiseki =

seiseki =

seiseki.name // ‘たかし’のこと

seiseki.score // 80 のこと

0

1

2

‘たかし’

‘国語’

80

name

subject

score

‘たかし’

‘国語’

80

箱に名前を付けられる

箱の名前で呼び出せる

インデックスで呼び出せる

195 of 440

オブジェクトのコード

function objectSample() {� var person = { id: 100, name: 'さかいも', food: 'フライドポテト' };� � // オブジェクトがログにどう表示されるか。� Logger.log(person);� � // nameを取り出す� Logger.log(person.name);� � // 書き換えることもできる� person.food = 'ラーメン';� Logger.log(person.food);� � // プロパティを追加することもできる� person.hobby = 'スプラトゥーン';� Logger.log(person);�}

person という名前のオブジェクトを生成。

プロパティ名として id,name,food があり、

それぞれのプロパティに値がある

196 of 440

オブジェクトのコード

var person = { id: 100, name: 'さかいも', food: 'フライドポテト' };

// ↑これは↓こう書いても同じ (改行しただけ)

var person = {� id: 100,� name: 'さかいも',� food: 'フライドポテト'�};

197 of 440

オブジェクトのコード

var person = { id: 100, name: 'さかいも', food: 'フライドポテト' };

// ↑これは↓こう書いても同じ (改行しただけ)

var person = {� id: 100,� name: 'さかいも',� food: 'フライドポテト'�};

id: 100

name: ‘さかいも’

food: ‘フライドポテト’

「personオブジェクト」

198 of 440

配列との違い

function arrayAndObject() {� var array = ['あ','い','う'];� var object = { id:100, name:'さかいも', food:'フライドポテト'};� � Logger.log(array);� Logger.log(object);�}

配列は順番どおり並んでる

オブジェクトは並び順は保証されていない。

(上ではidが最初だけどログはnameが最初)

199 of 440

オブジェクトの実験

「オブジェクト」のシートを追加

左記の表を作ってください。

データは1行でいいです!

200 of 440

コピペで実行だ!

function myObject() {� var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();� var sheet = spreadsheet.getSheetByName('オブジェクト');�� var person = {� id: sheet.getRange("A2").getValue(),� name: sheet.getRange("B2").getValue(),� food: sheet.getRange("C2").getValue(),� };�� var message = 'IDが'+person.id+'の' + person.name + � 'さんが好きな食べものは'+ person.food + 'です';�� sheet.getRange('A5').setValue(message);�}�

今回はログではなく、

スプレッドシートに

「出力」されます

201 of 440

コード解説

function myObject() {� var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();� var sheet = spreadsheet.getSheetByName('オブジェクト');�� var person = {� id: sheet.getRange("A2").getValue(),� name: sheet.getRange("B2").getValue(),� food: sheet.getRange("C2").getValue(),� };�� var message = 'IDが'+person.id+'の' + person.name + � 'さんが好きな食べものは'+ person.food + 'です';�� sheet.getRange('A5').setValue(message);�}�

シート名が「オブジェクト」になってるシートを取得する

202 of 440

コード解説

function myObject() {� var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();� var sheet = spreadsheet.getSheetByName('オブジェクト');�� var person = {� id: sheet.getRange("A2").getValue(),� name: sheet.getRange("B2").getValue(),� food: sheet.getRange("C2").getValue(),� };�� var message = 'IDが'+person.id+'の' + person.name + � 'さんが好きな食べものは'+ person.food + 'です';�� sheet.getRange('A5').setValue(message);�}�

セルから値を取得して、

personオブジェクトに入れていく.

key: value

203 of 440

コード解説

function myObject() {� var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();� var sheet = spreadsheet.getSheetByName('オブジェクト');�� var person = {� id: sheet.getRange("A2").getValue(),� name: sheet.getRange("B2").getValue(),� food: sheet.getRange("C2").getValue(),� };�� var message = 'IDが'+person.id+'の' + person.name + � 'さんが好きな食べものは'+ person.food + 'です';�� sheet.getRange('A5').setValue(message);�}

出力したい文字列を作る

204 of 440

コード解説

function myObject() {� var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();� var sheet = spreadsheet.getSheetByName('オブジェクト');�� var person = {� id: sheet.getRange("A2").getValue(),� name: sheet.getRange("B2").getValue(),� food: sheet.getRange("C2").getValue(),� };�� var message = 'IDが'+person.id+'の' + person.name + � 'さんが好きな食べものは'+ person.food + 'です';�� sheet.getRange('A5').setValue(message);�}

セルに出力する

205 of 440

オブジェクトの使いみち

例えば、テストの成績データを扱うとする。

seiseki = [たかし, 国語, 80];

seiseki = {

name: "たかし",

subject: "国語",

score: 80

};

配列で表現するとこうだけど

オブジェクトだとこう

206 of 440

オブジェクトの使いみち

例えば、テストの成績データを扱うとする。

seiseki = [たかし, 国語, 80];

seiseki = {

name: "たかし",

subject: "国語",

score: 80

};

配列だと

インデックスの[2]に点数が入ってる、を覚えておかないとならない。

seiseki[2]

オブジェクトだと

seiseki.score で点数が取得できる

207 of 440

データ型

208 of 440

Javascriptで扱えるデータ型

データ型

説明

サンプル

String

文字列。

var str = ‘あいうえお’;

Number

数値。整数も小数も。

var num = 100;

Boolean

真偽値。true か false

true または false

undefined

値が未定義なことを表す

null

特殊なキーワード(後述)

Object

オブジェクト

var person = {� name: ‘Bob’,� sex: ‘male’,� age: 25� }

209 of 440

「文字列」と「数字」は違う

function dataType() {� � var s = '3'; // Stringとしての3� var n = 5; // Numberとしての5� � // これらを足し算するとどうなるか?� Logger.log(s + n);�}

210 of 440

「文字列」と「数字」は違う

function dataType() {� � var s = '3'; // Stringとしての3� var n = 5; // Numberとしての5� � // これらを足し算するとどうなるか?� Logger.log(s + n);�}

文字列がある場合は

「文字列連結」になっちゃう。

211 of 440

文字列を数字に変換する関数

function dataType() {� � var s = '3';

var n = 5;� � // 文字列を数字に変換する parseInt()� Logger.log( parseInt(s, 10) + n );�}�

[javascript parseInt] で検索!!!

stringを、

10進法の数字にparseしろ

という命令

212 of 440

Boolean

Booleanとはtrueかfalseのこと。「てぃーあーるゆーいー」という文字列ではなく、true という値です。真か偽か、を表す値。�

function booleanTest() {� if ( 10 > 5 ) {� Logger.log( '10>5 は true' );� }� � if ( 'google' ) { //文字列はtrueと判断される� Logger.log( 'google はtrue' );� }� � if ( 'false' ) { // これは’false’という「文字列」� Logger.log( 'false(文字列)はtrue' );� }

if ( false ) { // これはBoolean値としての false� Logger.log( 'false(bool値)はどうかな' ); //これは出力されない。� }

if ( '' ) { //カラ文字はfalseになる!� Logger.log( 'から文字は?' ); //これは出力されない。� }�}�

[javascript falseになるもの] で検索!

213 of 440

特別な値 undefined, null

function undefTest() {� var test;� Logger.log(test);�}

function nullTest() {� var str = 'abc';� var m = str.match(/xyz/);� Logger.log(m);�}

match関数とは

str の中に ‘xyz’という文字列が含まれていたら

'xyz'を返す、という関数

214 of 440

特別な値 undefined, null

function undefTest() {� var test;� Logger.log(test);�}

function nullTest() {� var str = 'abc';� var m = str.match(/xyz/);� Logger.log(m);�}

「未定義であること(undefined)」

「該当する値がないこと(null)」

ここ が詳しく説明してる

215 of 440

関数

  • 変数…箱と中身
  • 算術演算子…数字の計算ができる
  • 文字列結合…文字列をくっつける
  • Javascriptのルール…コーディングする上でのルール
  • 条件分岐…もし●●だったら☓☓をする
  • 配列…大きな箱に複数の箱を入れられる
  • ループ…処理の繰り返し
  • 関数…処理をひとまとめにしておく
  • 組み込みオブジェクト…始めから用意されている「道具」

216 of 440

新しいスクリプトファイルを作成

名前を

「関数」

にしてください

217 of 440

「関数を呼び出す」ということ

function sono1() {� Logger.log('1.ここが実行されて');� sono2();� Logger.log('3.ここに戻ってくる');�}��function sono2() {� Logger.log('2.ここに来て');�}

sono1を実行してください

こういう順番で処理されます

218 of 440

コピペして「sayTest」を実行してログを見る

function sayTest() {� sayGoodBye();�}��function sayGoodBye() {� sayHello();� Logger.log('Good Bye!');�}��function sayHello() {� Logger.log('Hello!');�}

219 of 440

関数を呼ぶ、ということ(1)

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

function sayGoodBye() {� sayHello();� Logger.log('Good Bye!');�}

function sayTest() {

sayGoodBye();

}

1.Hello!が出力される

(続く)

220 of 440

関数を呼ぶ、ということ(2)

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

function sayGoodBye() {� sayHello();� Logger.log('Good Bye!');�}

function sayTest() {

sayGoodBye();

}

2.処理が終わったら

「呼び出し元」に戻る

(sayHello() の次の処理に移る)

3.Good Bye! が出力される

4.sayGoodByeの次の行に移る

(何も無いので終了)

221 of 440

実行順序の確認

function sayTest() { (1)� sayGoodBye(); (2)�}�(8) 終了

�function sayGoodBye() { (3)� sayHello(); (4)� Logger.log('Good Bye!'); (7)�}��function sayHello() { (5)� Logger.log('Hello!'); (6)�}

222 of 440

関数:「引数」と「戻り値」(speechを実行してみよう)

// 引数と戻り値の例�function speech() {� var name = 'sakaimo';� var speech = createSpeechText(name);� � Logger.log(speech);�}��function createSpeechText(name) {� var text = 'はじめまして、' + name + 'と申します';� return text;�}

223 of 440

関数:「引数」と「戻り値」

// 引数と戻り値の例�function speech() {� var name = 'sakaimo';� var speech = createSpeechText(name);� � Logger.log(speech);�}��function createSpeechText(name) {� var text = 'はじめまして、' + name + 'と申します';� return text;�}

関数に渡す値 (=実引数)

関数が呼び出し元に返す値(=戻り値)

関数定義に書く引数 (=仮引数)

224 of 440

デバッグしてみよう

1.var name にブレイクポイントを付けて

2.speech関数を「デバッグ」する

3.「ステップイン」を押して1行ずつ進める

4.この時点で変数nameに何が入っているかを確認することができる!!

225 of 440

関数の例:三角形の面積を求めるプログラム

「底辺」と「高さ」から「三角形の面積」を計算する君をつくる。

求めたい三角形の面積が2つあるとする。

226 of 440

イメージ図

底辺 10

高さ 20

答え

100

底辺 30

高さ 40

答え

600

底辺 ✕ 高さ ÷ 2

底辺 ✕ 高さ ÷ 2

227 of 440

イメージ図+ベタに書くとこうなる

底辺 10

高さ 20

答え

100

底辺 30

高さ 40

答え

600

底辺 ✕ 高さ ÷ 2

底辺 ✕ 高さ ÷ 2

228 of 440

イメージ図+ベタに書くとこうなる

底辺 10

高さ 20

答え

100

底辺 30

高さ 40

答え

600

底辺 ✕ 高さ ÷ 2

底辺 ✕ 高さ ÷ 2

底辺 ✕ 高さ ÷ 2

底辺 ✕ 高さ ÷ 2

三角形の面積を計算する

という処理は同じ

229 of 440

共通の処理を切り出しておく

→「関数」を作る

面積計算してくれる君

インプット

高さ

底辺

処理

底辺 ✕ 高さ ÷ 2

アウトプット

面積

(2)インプットを受け取る

(3)計算する

(4)結果を返す

(1)関数の名前

230 of 440

共通の処理を切り出しておく

→「関数」を作る

底辺 10

高さ 20

答え

100

底辺 30

高さ 40

答え

600

底辺と高さを渡すと

三角形の面積を返してくれる

面積計算してくれる君

インプット

高さ

底辺

処理

底辺 ✕ 高さ ÷ 2

アウトプット

面積

231 of 440

コードにするとこうなる(書いてみよう)

function calcTriangleArea(base, height) {� var area = base * height / 2;� return area;�}

232 of 440

コード解説

function calcTriangleArea(base, height) {� var area = base * height / 2;� return area;�}

(1)関数の名前

(2)インプットを受け取る

(3)計算する

(4)結果を返す

233 of 440

関数を使うには「呼び出す」

function triangleArea2() {� var area1 = calcTriangleArea(10, 20);� Logger.log('1の面積=' + area1);� � var area2 = calcTriangleArea(30, 40);� Logger.log('2の面積=' + area2);�}��function calcTriangleArea(base, height) {� var area = base * height / 2;� return area;�}

面積計算してくれる君に

10と20を渡す

base = 10

height = 20

になる

234 of 440

コード解説

function triangleArea2() {� var area1 = calcTriangleArea(10, 20);� Logger.log('1の面積=' + area1);� � var area2 = calcTriangleArea(30, 40);� Logger.log('2の面積=' + area2);�}��function calcTriangleArea(base, height) {� var area = base * height / 2;� return area;�}

base とheight で計算して、

areaに代入する

235 of 440

コード解説

function triangleArea2() {� var area1 = calcTriangleArea(10, 20);� Logger.log('1の面積=' + area1);� � var area2 = calcTriangleArea(30, 40);� Logger.log('2の面積=' + area2);�}��function calcTriangleArea(base, height) {� var area = base * height / 2;� return area;�}

呼び出し元に

結果をreturnする

area1 に結果が代入される

236 of 440

before

after

底辺 10

高さ 20

答え

100

底辺 30

高さ 40

答え

600

底辺 10

高さ 20

答え

100

底辺 30

高さ 40

答え

600

底辺 ✕ 高さ ÷ 2

底辺 ✕ 高さ ÷ 2

底辺 ✕ 高さ ÷ 2

面積計算してくれる君

237 of 440

関数のメリット1:使いまわせる

底辺 10

高さ 20

答え

100

底辺 30

高さ 40

答え

600

底辺 10

高さ 20

答え

100

底辺 30

高さ 40

答え

600

底辺 ✕ 高さ ÷ 2

底辺 ✕ 高さ ÷ 2

底辺 ✕ 高さ ÷ 2

面積計算してくれる君

3つ目の三角形が必要になっても、

底辺と高さを渡せばいいだけ

238 of 440

関数のメリット1:使いまわせる

底辺 10

高さ 20

答え

100

底辺 30

高さ 40

答え

600

底辺 10

高さ 20

答え

100

底辺 30

高さ 40

答え

600

底辺 ✕ 高さ ÷ 2

底辺 ✕ 高さ ÷ 2

底辺 ✕ 高さ ÷ 2

面積計算してくれる君

<使う側>

使いたい関数を呼ぶ

必要なら引数を渡す

だけで、結果がもらえる。

関数の中がどうなってるのかは

知らなくていい

<関数>

引数を受け取って

計算して

結果をreturnする

呼び出す(引数)

結果を返す

239 of 440

関数のメリット2:修正が一箇所で済む

底辺 10

高さ 20

答え

66.666

底辺 30

高さ 40

答え

400

底辺 10

高さ 20

答え

100

底辺 30

高さ 40

答え

600

底辺 ✕ 高さ ÷ 3

底辺 ✕ 高さ ÷ 3

底辺 ✕ 高さ ÷ 2

面積計算してくれる君

(そんなことないけど)

三角形の面積の公式が変わった場合

すべての計算箇所を修正する

ここも修正する必要あり

240 of 440

関数のメリット2:修正が一箇所で済む

底辺 10

高さ 20

答え

100

底辺 30

高さ 40

答え

600

底辺 10

高さ 20

答え

66.6

底辺 30

高さ 40

答え

400

底辺 ✕ 高さ ÷ 3

底辺 ✕ 高さ ÷ 3

底辺 ✕ 高さ ÷ 3

面積計算してくれる君

まとまっていれば

一箇所の修正でいい

241 of 440

引数は配列やオブジェクトでもいい

function seiseki() {� //テスト成績のオブジェクト� var test= {� subject: '国語',� score: 85� };� � // 結果をチェックしてもらう

if (checkTest(test)) {� Logger.log('合格');� }else{� Logger.log('不合格');� }�}�

// 60点以上だったら合格、という仕様�function checkTest(test) {� if(test.score >= 60) {� return true;� } else {� return false;

}�}

242 of 440

ちょっと補足

function seiseki() {� //テスト成績のオブジェクト� var test= {� subject: '国語',� score: 85� };� � // 結果をチェックしてもらう� if (checkTest(test)) {� Logger.log('合格');� }else{� Logger.log('不合格');� }�}�

// 60点以上だったら合格、という仕様�function checkTest(test) {� if(test.score >= 60) {� return true;� } else {� return false;

}�}

ここ値を「仮引数」という.

自由でいいに決めていい.

243 of 440

ちょっと補足

function seiseki() {� //テスト成績のオブジェクト� var test= {� subject: '国語',� score: 85� };� � // 親に見せる� if (checkTest(test)) {� Logger.log('合格');� }else{� Logger.log('不合格');� }�}�

// 60点以上だったら合格、という仕様�function checkTest(data) {� if(data.score >= 60) {� return true;� } else {� return false;

}�}

受け取り側で自由に名前をきめていい

呼び出し側が「test」であっても

244 of 440

関数で課題

(ここまでの総復習的な)

245 of 440

たかし君のテスト再び (問題文は全く同じ)

たかし君は国語、算数、英語のテストを受けました。

国語は80点、算数が100点、英語は60点でした。

この学校では3教科の平均によって下記のように成績が決まっています

  • 80点以上:優
  • 60点以上80点未満:良
  • 40点以上60点未満:可
  • 40点未満:不可

また、お母さんから「平均点が75点以上だったらお小遣いup」を約束されています。

たかし君の各教科の成績に応じて、

  • 成績
  • お小遣いアップできるか否か

を出力するプログラムを書きなさい。ただし出力は下記のフォーマットとする

今回のたかし君の平均点は●点です。

よって成績は「●(優、良、可、不可のいずれか)」でした。

お小遣いアップ(「できました。」あるいは「できませんでした。」)

246 of 440

お題:30分

たかし君のテストの成績は「配列」になっています。

var score = [100, 80, 90];

<課題その1>

3教科の点数が入った配列を引数として渡すと、成績を判定して優,良,可,不可 のいずれかの文字列を返す関数 checkSeiseki を作りなさい。

<課題その2>

平均点を引数として渡すと、お小遣いup可能かどうかを返す関数 canMoneyUp を作りなさい。up可能な場合true, 不可能な場合falseを返します。

247 of 440

実行するのは takashiTest()

function takashiTest() {� var score = [100, 80, 90];

}

function checkSeiseki(xxx) {�

}

function canMoneyUp(xxx) {�

}

248 of 440

「やること」を日本語で書いてみる

249 of 440

その1をどう書くか

function takashiTest() {� var score = [100, 80, 90];

//その1:成績の配列を渡すと判定結果をくれる

var hantei = checkSeiseki(score);

}

<その1>

3教科の点数が入った配列を引数として渡すと、成績を判定して優,良,可,不可 のいずれかの文字列を返す関数 checkSeiseki を作りなさい。

250 of 440

checkSeisekiでは何をするか

function takashiTest() {� var score = [100, 80, 90];

//その1:成績の配列を渡すと判定結果をくれる

var hantei = checkSeiseki(score);

}

function checkSeiseki(score) {� // scoreの中身の平均を出す

// 平均点に応じて優良可不可を判定 (既出)

// 結果(優,良,可,不可)を return する

}

仕様

3教科の点数が入った配列を引数として渡すと、成績を判定して優,良,可,不可 のいずれかの文字列を返す

251 of 440

return の結果が hantei に入る

function takashiTest() {� var score = [100, 80, 90];

//その1:成績の配列を渡すと判定結果をくれる

var hantei = checkSeiseki(score);

}

function checkSeiseki(score) {� // scoreの中身の平均を出す

// 平均点に応じて優良可不可を判定 (既出)

// 結果(優,良,可,不可)を return する

}

「優,良,可,不可]のいずれかが

hanteiに代入される

252 of 440

その2は何をするのか

function takashiTest() {� var score = [100, 80, 90];

//その1:成績の配列を渡すと判定結果をくれる

var hantei = checkSeiseki(score);

// その2:平均点を渡すと小遣いupの可否をくれる

// 2-1.まず平均点を出す

var average = ...

}

function checkSeiseki(score) {� // scoreの中身の平均を出す

// 平均点に応じて優良可不可を判定 (既出)

// 結果(優,良,可,不可)を return する

}

253 of 440

canMoneyUpでは何をするか

function takashiTest() {� var score = [100, 80, 90];

//その1:成績の配列を渡すと判定結果をくれる

var hantei = checkSeiseki(score);

// その2:平均点を渡すと小遣いupの可否をくれる

// 2-1.まず平均点を出す

var average = ...

// 2-2.平均点を渡す

var up = canMoneyUp(average);

}

function checkSeiseki(score) {� // scoreの中身の平均を出す

// 平均点に応じて優良可不可を判定 (既出)

// 結果を return する

}

function canMoneyUp(average) {� // 75点以上かどうかを判定

// 結果(true/false)をreturnする

}

仕様

平均点を引数として渡すと、

お小遣いup可能かどうかを返す

254 of 440

結果を出力する (回答例はコメント欄に)

function takashiTest() {� var score = [100, 80, 90];

//その1:成績の配列を渡すと判定結果をくれる

var hantei = checkSeiseki(score);

// その2:平均点を渡すと小遣いupの可否をくれる

// 2-1.まず平均点を出す

var average = ...

// 2-2.平均点を渡す

var up = canMoneyUp(average);

// 結果を出力する

}

function checkSeiseki(score) {� // scoreの中身の平均を出す

// 平均点に応じて優良可不可を判定 (既出)

// 結果(優,良,可,不可)を return する

}

function canMoneyUp(average) {� // 75点以上かどうかを判定

// 結果(true/false)をreturnする

}

255 of 440

プログラムの改善ポイントがあるよね?

function takashiTest() {� var score = [100, 80, 90];

//その1:成績の配列を渡すと判定結果をくれる

var hantei = checkSeiseki(score);

// その2:平均点を渡すと小遣いupの可否をくれる

// 2-1.まず平均点を出す

var average = ...

// 2-2.平均点を渡す

var up = canMoneyUp(average);

// 結果を出力する

}

function checkSeiseki(score) {� // scoreの中身の平均を出す

// 平均点に応じて優良可不可を判定 (既出)

// 結果(優,良,可,不可)を return する

}

function canMoneyUp(average) {� // 75点以上かどうかを判定

// 結果(true/false)をreturnする

}

同じことを2回やってる!

→これをどうにかしてください。

256 of 440

任意課題:配列を受け取って平均を返す関数を追加しなさい

function takashiTest() {� var score = [100, 80, 90];

//その1:成績の配列を渡すと判定結果をくれる

var hantei = checkSeiseki(score);

// その2:平均点を渡すと小遣いupの可否をくれる

// 2-1.まず平均点を出す

var average = ...

// 2-2.平均点を渡す

var up = canMoneyUp(average);

// 結果を出力する

}

function checkSeiseki(score) {� // scoreの中身の平均を出す

// 平均点に応じて優良可不可を判定 (既出)

// 結果(優,良,可,不可)を return する

}

function canMoneyUp(average) {� // 75点以上かどうかを判定

// 結果(true/false)をreturnする

}

257 of 440

スコープ

258 of 440

新しいスクリプトファイルを作成

名前を

「スコープ」

にしてください

259 of 440

スコープとは

変数の有効範囲、のこと。

宣言した変数が、どこから参照できるか/できないか

が決まっています。

260 of 440

関数の外に書く

var msg = 'Good Morning.';�Logger.log(msg);��function scopeTest() {� Logger.log('Hello.');�}��Logger.log('Good Bye.');

実行するのはこの関数

関数の外にあるコード

関数の外にあるコード

261 of 440

実行順序がこうなった

var msg = 'Good Morning.';�Logger.log(msg); (1)��function scopeTest() {� Logger.log('Hello.'); (3)�}��Logger.log('Good Bye.'); (2)

262 of 440

グローバル領域が先に実行されるというルール。

var msg = 'Good Morning.';�Logger.log(msg);��function scopeTest() {� Logger.log('Hello.');�}��Logger.log('Good Bye.');

関数

関数の外

=グローバル領域

呼び出した関数よりも先に、グローバル領域が上から順番に実行される。

※ 理由がない限りはグローバル領域には書かないほうがいい!

263 of 440

グローバルスコープとローカルスコープ

var globalMsg = 'Globalです';��function scopeTest1() {� var localMsg = 'Localです';�}��function scopeTest2() {� Logger.log(globalMsg);� Logger.log(localMsg);�}

さっき書いたスクリプトを削除してから下記を書く

実行するのはこの関数

264 of 440

エラーになる

scopeTest1の中で宣言された localMsgは、

その関数の外からは参照できない。

265 of 440

別スコープにある同じ名前の変数

var msg = 'Globalです';��function scopeTest1() {� var localMsg = 'Local その1です';�}��function scopeTest2() {� var localMsg = 'Local その2です';� Logger.log(localMsg);�}

これはOK

scopeTest1とは別の

の変数になる

266 of 440

問題:下記では何が出力されますか?

var msg = 'Globalです';��function scopeTest3() {� var msg = 'Localです';� Logger.log(msg); //ココでは何が出力されますか?�}

267 of 440

答え: Localです

var msg = 'Globalです';��function scopeTest3() {� var msg = 'Localです';� Logger.log(msg);�}

自分に近い方が優先される

268 of 440

ここまでで「キホン」終わり

...長かったよね。

269 of 440

ここまでで土台ができました。

[土台]

GAS(プログラム言語)のキホン

270 of 440

次は各アプリケーション特有の「使い方」をやります

[土台]

GAS(プログラム言語)のキホン

271 of 440

どゆこと? 例)スプレッドシートの場合

[土台]

GAS(プログラム言語)のキホン

シートから値を取ってくる

シートに値を入力する

シートをコピーする

...など「スプレッドシート」を操作する

272 of 440

↓GASだけどスプレッドシートは使ってない例

function sayTest() {� sayGoodBye();�}��function sayGoodBye() {� sayHello();� Logger.log('Good Bye!');�}��function sayHello() {� Logger.log('Hello!');�}

スプレッドシートに紐づく「スクリプトエディタ」にコードを書いていますが、

コードからスプレッドシートにアクセスはしていない。

という意味です。

273 of 440

↓GASからスプレッドシートにアクセスしている例

function testIf() {� var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();� var x = Browser.inputBox('数字を入れよう', Browser.Buttons.OK_CANCEL);�� if ( x < 10 ) {� sheet.getRange("A5").setValue(x + 'は10より小さい');� } else if (x < 20 ) {� sheet.getRange("A5").setValue(x + 'が20より小さい');� } else {� sheet.getRange("A5").setValue(x + 'は20以上');� }�}

スプレッドシートに対して「操作」している

274 of 440

「操作する」って言っても難しくない

すでに学んだ「関数」が用意されています。

それを「使う」だけです。

自分で書いたGAS

シートのデータちょうだい

はいどうぞ

(例)

sheet.getRange("A5").getValue()

シートのA5にある値をちょうだい、という関数

275 of 440

つまりはこれと同じこと

底辺 10

高さ 20

答え

100

底辺 30

高さ 40

答え

600

底辺 ✕ 高さ ÷ 2

面積計算してくれる君

276 of 440

スプレッドシート

(これ以降、「SS」はスプレッドシートのことね)

277 of 440

新しいスクリプトファイルを作成

名前を

「スプレッドシート」

にしてください

278 of 440

SSの構造

1)スプレッドシートアプリケーション

(Officeでいうところの「エクセル」)

2)スプレッドシート

(ブックのこと)

3)シート

(シートのこと)

4)レンジ (セルの範囲)

279 of 440

SSでやりたいことってだいたいこの3つ

  • シートからある範囲の値を取ってきて (値のget)
  • 何らかの処理をして
  • あるセルに書き出す (値のset)

280 of 440

サンプル

function getAndSet() {� var ss = SpreadsheetApp.getActiveSpreadsheet();� var sheet = ss.getSheetByName('スプレッドシート');�

var range = sheet.getRange("A1");�

var value = range.getValue();�

� range.setValue(value + 'っていいよね。');�}

1)シートを追加して

2)A1に何か書いてください

281 of 440

サンプル(解説)

function getAndSet() {� var ss = SpreadsheetApp.getActiveSpreadsheet();� var sheet = ss.getSheetByName('スプレッドシート');�

var range = sheet.getRange("A1");�

var value = range.getValue();�

� range.setValue(value + 'っていいよね。');�}

1)スプレッドシートアプリケーションから

2)ssを取得(get)する

2)ssから、3)シートを取得する

3)シートから4)レンジを取得する

4)レンジは「範囲」なので、

その中にある「値」を取得する

5)レンジに対してValueをSetする

282 of 440

サンプル(解説)

function getAndSet() {� var ss = SpreadsheetApp.getActiveSpreadsheet();� var sheet = ss.getSheetByName('スプレッドシート');�

var range = sheet.getRange("A1");�

var value = range.getValue();�

� range.setValue(value + 'っていいよね。');�}

1)スプレッドシートアプリケーションから

2)ssを取得(get)する

2)ssから、3)シートを取得する

3)シートから4)レンジを取得する

4)レンジは「範囲」なので、

その中にある「値」を取得する

5)レンジに対してValueをSetする

この処理は定番処理なので丸覚えしてください

処理をしたい「シート」を特定するコードです

283 of 440

ポイント

function getAndSet() {� var ss = SpreadsheetApp.getActiveSpreadsheet();� var sheet = ss.getSheetByName('スプレッドシート');�

var range = sheet.getRange("A1");�

var value = range.getValue();�

� range.setValue(value + 'っていいよね。');�}

1)スプレッドシートアプリケーションから

2)ssを取得(get)する

2)ssから、3)シートを取得する

3)シートから4)レンジを取得する

4)レンジは「範囲」なので、

その中にある「値」を取得する

5)レンジに対してValueをSetする

たぶん「レンジ」って

馴染みがない思う。

“B12” とか “A3:G30” とかのこと。

GASではRangeに対してget、setする。

284 of 440

(余談) まとめて書ける

function getAndSet() {� var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();

var sheet = spreadsheet.getSheetByName('スプレッドシート');

var range = sheet.getRange("A1");

var value = range.getValue();� range.setValue(value + 'っていいよね。');�}�

まとめて1行でも書ける

var value = sheet.getRange("A1").getValue();

赤字部分が range

285 of 440

値の取得(複数のセル)

前ページのやり方だと、”A1”のセルしか取得できない。

実務では「範囲指定をせずに」

  • シートの中にあるデータを全部取ってくる

をやります。以前やった「二次元配列」の再登場。

これから出てくるサンプルプログラムでやってみましょう。

286 of 440

リファレンスの見方

ココ↓に遷移します

https://developers.google.com/apps-script/reference/calendar/

[GoogleAppsScript リファレンス」で検索

287 of 440

スプレッドシートのリファレンス

288 of 440

うわ!英語かよ!わかんねぇよ!と思ったあなた

「GAS スプレッドシート 使い方」で検索だ。

いっぱいHITするのでそれを見てもいいと思う。

ただ、間違ってたり情報が古かったりするので、

「公式」な情報は

https://developers.google.com/apps-script/reference/

にある、というのは知っておいてください。

289 of 440

スプレッドシート実践 その1

(シートのデータを全部取ってきて処理する)

290 of 440

アンケートの集計GAS

やりたいこと

  • 「ランチに食べたいもの」アンケートの集計表がある
  • 「中華」「和食」「洋食」が何票あるか集計したい
  • 集計した結果をメール送信したい

アンケート結果は

- 中華 3人

- 和食 2人

- 洋食 5人

でした。

メール送信

291 of 440

アンケートの集計GAS

やりたいこと

  • 「ランチに食べたいもの」アンケートの集計表がある
  • 「中華」「和食」「洋食」が何票あるか集計したい
  • 集計した結果をメール送信したい

アンケート結果は

- 中華 3人

- 和食 2人

- 洋食 5人

でした。

メール送信

集計だけなら関数でできるね!

=countif(B2:B11,"中華")

今回はあえてGASでやるよ。

292 of 440

まずは日本語で考える

大きな「処理」の塊で考えると

「集計」して「メールする」

あたりまえに聞こえるけど、

ちゃんと「わけて」考えておく。

名前

食べたいもの

沼田悠花

中華

室井千代乃

和食

中澤和歌子

洋食

石本春夫

洋食

菅谷優子

洋食

米山英明

洋食

大和田敏嗣

和食

倉持英司

中華

伴敏嗣

洋食

織田雄太

中華

コピペ用。皆さんA1からコピペしてください

293 of 440

すこし細かく日本語で考える

集計の部分

  • 1行目は不要だな(ヘッダーだから)
  • 2行目から11行目のB列が知りたいこと
  • (今は11行目だけど回答者が増えるかもしれない)
  • B列を1行ずつ調べて、中華、和食、洋食をカウントアップすればいいかな

メール送信部分

  • 集計結果をメールする
    • TO,件名,本文

名前

食べたいもの

沼田悠花

中華

室井千代乃

和食

中澤和歌子

洋食

石本春夫

洋食

菅谷優子

洋食

米山英明

洋食

大和田敏嗣

和食

倉持英司

中華

伴敏嗣

洋食

織田雄太

中華

コピペ用。皆さんA1からコピペしてください

294 of 440

スクリプトエディタに「日本語で」手順を書く

function sendMailForLunchQuestionnaire() {� // sheetを特定� � // シート内のすべてのデータを取得する�� // chinese, japanese, western っていうカウンタに数えた結果を入れていこう� � // 1行ずつ、B列をみて、chinese, japanese, westernのどれかに1を足していく� � // 全部数え終わったらメール送信する�}

295 of 440

日本語で書く

function sendMailForLunchQuestionnaire() {� // sheetを特定� � // シート内のすべてのデータを取得する�� // chinese, japanese, western っていうカウンタに数えた結果を入れていこう� � // 1行ずつ、B列をみて、chinese, japanese, westernのどれかに1を足していく� � // 全部数え終わったらメール送信する�}

そもそもこれが浮かばないよ!

という方、大丈夫。当たり前です。

プログラムに関わらず、同じような経験をしたことがあれば、次に出会った時にだいたい予想できるでしょ?それと同じ。いっぱい書いてください。

296 of 440

日本語で書く

function sendMailForLunchQuestionnaire() {� // sheetを特定� var ss= SpreadsheetApp.getActiveSpreadsheet();� var sheet = ss.getSheetByName('スプレッドシート');� � // シート内のすべてのデータを取得する� var data = sheet.getDataRange().getValues();� � Logger.log(data); // dataの中身が何なのかを見てみたくなる� � // chinese, japanese, western っていうカウンタに数えた結果を入れていこう� // 1行ずつ、B列をみて、chinese, japanese, westernのどれかに1を足していく� // 全部数え終わったらメール送信する�}

297 of 440

日本語で書く

function sendMailForLunchQuestionnaire() {� // sheetを特定するまでの決まりパターンでsheetを特定� var ss= SpreadsheetApp.getActiveSpreadsheet();� var sheet = ss.getSheetByName('スプレッドシート');� � // シート内のすべてのデータを取得する� var data = sheet.getDataRange().getValues();� � Logger.log(data); // dataの中身が何なのかを見てみたくなる� � // chinese, japanese, western っていうカウンタに数えた結果を入れていこう� // 1行ずつ、B列をみて、chinese, japanese, westernのどれかに1を足していく� // 全部数え終わったらメール送信する�}

「シート内のすべてのデータ」

というのはコレのこと

298 of 440

そう、二次元配列だね!

var data = [

[名前, 食べたいもの],

[沼田悠花, 中華],

[室井千代乃, 和食],

[中澤和歌子, 洋食],

[石本春夫, 洋食],

[菅谷優子, 洋食],

[米山英明, 洋食],

[大和田敏嗣, 和食],

[倉持英司, 中華],

[伴敏嗣, 洋食],

[織田雄太, 中華]

];

299 of 440

そう、二次元配列だね!

var data = [

[名前, 食べたいもの],

[沼田悠花, 中華],

[室井千代乃, 和食],

[中澤和歌子, 洋食],

[石本春夫, 洋食],

[菅谷優子, 洋食],

[米山英明, 洋食],

[大和田敏嗣, 和食],

[倉持英司, 中華],

[伴敏嗣, 洋食],

[織田雄太, 中華]

];

dataという配列

data[0]

data[1]

data[2]

data[5][1]

300 of 440

デバッグモードでも中身は確認できます

(1) ブレイクポイント

(2) デバッグ実行

→ブレイクポイントでプログラムが止まる

(3) その時点での変数の中身が見える。

例) data[1][1]が “中華” だと分かる

301 of 440

二次元配列を一つずつ処理する

function sendMailForLunchQuestionnaire() {� // sheetを特定するまでの決まりパターンでsheetを特定� var ss= SpreadsheetApp.getActiveSpreadsheet();� var sheet = ss.getSheetByName('スプレッドシート');� � // シート内のすべてのデータを取得する� var data = sheet.getDataRange().getValues();�� // chinese, japanese, western っていうカウンタに数えた結果を入れていこう� var chinese = 0, japanese = 0, western = 0; //一気に宣言+初期化できる� � // 1行ずつ、B列をみて、chinese, japanese, westernのどれかに1を足していく� // ただし、最初の行はスルーする(ヘッダーだから) for (var i = 1; i < data.length; i++) {� Logger.log(data[i][1]);� }� � // 全部数え終わったらメール送信する�}

302 of 440

欲しいデータを取り出す

function sendMailForLunchQuestionnaire() {� // sheetを特定するまでの決まりパターンでsheetを特定� var ss= SpreadsheetApp.getActiveSpreadsheet();� var sheet = ss.getSheetByName('スプレッドシート');� � // シート内のすべてのデータを取得する� var data = sheet.getDataRange().getValues();�� // chinese, japanese, western っていうカウンタに数えた結果を入れていこう� var chinese = 0, japanese = 0, western = 0; //一気に宣言+初期化できる� � // 1行ずつ、B列をみて、chinese, japanese, westernのどれかに1を足していく� // ただし、最初の行はスルーする(ヘッダーだから) for (var i = 1; i < data.length; i++) {� Logger.log(data[i][1]);� }� � // 全部数え終わったらメール送信する�}

ログの結果

これをカウントする

303 of 440

(補足) for内でやってること

var data = [

[名前, 食べたいもの],

[沼田悠花, 中華],

[室井千代乃, 和食],

[中澤和歌子, 洋食],

[石本春夫, 洋食],

[菅谷優子, 洋食],

[米山英明, 洋食],

[大和田敏嗣, 和食],

[倉持英司, 中華],

[伴敏嗣, 洋食],

[織田雄太, 中華]

];

for (var i = 1; i < data.length; i++) {� Logger.log(data[i][1]);�}

iが1の時

data[1]

304 of 440

(補足) for内でやってること

var data = [

[名前, 食べたいもの],

[沼田悠花, 中華],

[室井千代乃, 和食],

[中澤和歌子, 洋食],

[石本春夫, 洋食],

[菅谷優子, 洋食],

[米山英明, 洋食],

[大和田敏嗣, 和食],

[倉持英司, 中華],

[伴敏嗣, 洋食],

[織田雄太, 中華]

];

for (var i = 1; i < data.length; i++) {� Logger.log(data[i][1]);�}

iが2の時

data[2]

305 of 440

(補足) for内でやってること

var data = [

[名前, 食べたいもの],

[沼田悠花, 中華],

[室井千代乃, 和食],

[中澤和歌子, 洋食],

[石本春夫, 洋食],

[菅谷優子, 洋食],

[米山英明, 洋食],

[大和田敏嗣, 和食],

[倉持英司, 中華],

[伴敏嗣, 洋食],

[織田雄太, 中華]

];

for (var i = 1; i < data.length; i++) {� Logger.log(data[i][1]);�}

iが3の時

data[3]

306 of 440

(補足) for内でやってること

var data = [

[名前, 食べたいもの],

[沼田悠花, 中華],

[室井千代乃, 和食],

[中澤和歌子, 洋食],

[石本春夫, 洋食],

[菅谷優子, 洋食],

[米山英明, 洋食],

[大和田敏嗣, 和食],

[倉持英司, 中華],

[伴敏嗣, 洋食],

[織田雄太, 中華]

];

for (var i = 1; i < data.length; i++) {� Logger.log(data[i][1]);�}

iが3の時

data[3]

このとき

data[3][1]には

"洋食"が入ってる

307 of 440

中華、和食、洋食をカウントするには?(1)

// 1行ずつ、B列をみて、chinese, japanese, westernのどれかに1を足していく� // ただし、1行目はスルーする� for (var i = 1; i < data.length; i++) {� var food = data[i][1];� if (food === "中華") {� chinese++;� } else if(food === "和食") {� japanese++;� } else if(food === "洋食") {� western++;� }}� Logger.log("中華: " + chinese);� Logger.log("和食: " + japanese);� Logger.log("洋食: " + western);

「食事ジャンル」を

food に代入しとく

308 of 440

中華、和食、洋食をカウントするには?(1)

// 1行ずつ、B列をみて、chinese, japanese, westernのどれかに1を足していく� // ただし、1行目はスルーする� for (var i = 1; i < data.length; i++) {� var food = data[i][1];� if (food === "中華") {� chinese++;� } else if(food === "和食") {� japanese++;� } else if(food === "洋食") {� western++;� }� }� Logger.log("中華: " + chinese);� Logger.log("和食: " + japanese);� Logger.log("洋食: " + western);

foodが中華なら、和食なら、洋食なら、、、

条件分岐といえばifだね

309 of 440

(補足)教えてなかった switch文

// 1行ずつ、B列をみて、chinese, japanese, westernのどれかに1を足していく� // ただし、1行目はスルーする� for (var i = 1; i < data.length; i++) {� switch(data[i][1]) {� case "中華":� chinese++;� break;� case "和食":� japanese++;� break;� case "洋食":� western++;� break;� }� }

条件分岐には

switch文というのもある。

詳しくは調べてみてね!

310 of 440

ひとまずここまでの全体コード(下のノート欄にあるよ)

function sendMailForLunchQuestionnaire() {� // sheetを特定するまでの決まりパターンでsheetを特定� var ss = SpreadsheetApp.getActiveSpreadsheet();� var sheet = ss.getSheetByName('スプレッドシート');� � // シート内のすべてのデータを取得する� var data = sheet.getDataRange().getValues();�� // chinese, japanese, western っていうカウンタに数えた結果を入れていこう� var chinese = 0, japanese = 0, western = 0;� � // 1行ずつ、B列をみて、chinese, japanese, westernのどれかに1を足していく� // ただし、1行目はスルーする� for (var i = 1; i < data.length; i++) {� var food = data[i][1];� if (food === "中華") {� chinese++;� } else if(food === "和食") {� japanese++;� } else if(food === "洋食") {� western++;� }

}

//右につづく

// この出力は動作確認のためのログ � Logger.log("中華: " + chinese);� Logger.log("和食: " + japanese);� Logger.log("洋食: " + western);� � // 全部数え終わったらメール送信する�}

ここまでで「集計する」ができた

311 of 440

メール本文を作成して、メールを送る

// 全部数え終わったらメール送信する

// メールの作成

var body = 'アンケート結果は\n' +

' -中華' + chinese + '人\n' +

' -和食' + japanese + '人\n' +

' -洋食' + western + '人\n' +

'でした。';

var to = '自分のメアドを書いてください';

var subject = 'ランチアンケートの結果です';

// メール送信

GmailApp.sendEmail(to, subject, body);

312 of 440

メール本文を作成して、メールを送る

// 全部数え終わったらメール送信する

// メールの作成

var body = 'アンケート結果は\n' +

' -中華' + chinese + '人\n' +

' -和食' + japanese + '人\n' +

' -洋食' + western + '人\n' +

'でした。';

var to = '自分のメアドを書いてください';

var subject = 'ランチアンケートの結果です';

// メール送信

GmailApp.sendEmail(to, subject, body);

メールの「本文」を作ってる

313 of 440

メール本文を作成して、メールを送る

// 全部数え終わったらメール送信する

// メールの作成

var body = 'アンケート結果は\n' +

' -中華' + chinese + '人\n' +

' -和食' + japanese + '人\n' +

' -洋食' + western + '人\n' +

'でした。';

var to = '自分のメアドを書いてください';

var subject = 'ランチアンケートの結果です';

// メール送信

GmailApp.sendEmail(to, subject, body);

宛先(to)と件名(subject)

を作ってる

314 of 440

メール本文を作成して、メールを送る

// 全部数え終わったらメール送信する

// メールの作成

var body = 'アンケート結果は\n' +

' -中華' + chinese + '人\n' +

' -和食' + japanese + '人\n' +

' -洋食' + western + '人\n' +

'でした。';

var to = '自分のメアドを書いてください';

var subject = 'ランチアンケートの結果です';

// メール送信

GmailApp.sendEmail(to, subject, body);

(ssではなく)Gmailアプリを呼び出して、

sendMailという関数を使っている。

この関数に引数としてto, subject, body を渡すと、

そのとおりにメールを送信してくれるという関数

このスライドのメモ欄にコード貼っときます↓

315 of 440

実践での注意点

こういうことが起こると正しく動作しなくなるよ、の例

  • 誰かが1行目を「不要」だと思って削除したら
  • 逆に1行目の上に行を追加したら
  • A列の左、あるいはB列の左に列を追加されたら
  • 「中華」「和食」「洋食」以外の文字列が来たら
  • シート名を変更されたら
  • メール送信先の人が退社したら(通知が届かないよね)

→実務で使う場合に問題になる!

316 of 440

対策例

  • 1行目を「不要」だと思って削除したら →削除できないようにしておく
  • 逆に1行目の上に行を追加したら →追加できないようにしておく
  • A列の左、あるいはB列の左に列を追加されたら →同上
  • 「中華」「和食」「洋食」以外の文字列が来たら →入力規則で縛る
  • シート名を変更されたら →変更できないようにしておく
  • メール送信先の人が退社したら(通知が届かないよね) →送信先をMLにする

私がよくやるのは「意図したようなフォーマットになってることをチェックするスクリプト」を書いて、エラーがあったら知らせる(msgBoxやメール)

317 of 440

機能追加 課題1 (任意)

集計結果をメールではなく、

スプレッドシートに書き出すようにする。

318 of 440

機能追加 課題2 (任意)

男女別にも結果を出力したい

こんな感じ↓

アンケート結果は� -中華3人� -和食2人� -洋食5人�

<内訳>

男性

-中華2人

-和食1人

-洋食3人

女性

-中華1人

-和食1人

-洋食2人

名前

食べたいもの

性別

沼田悠花

中華

室井千代乃

和食

中澤和歌子

洋食

石本春夫

洋食

菅谷優子

洋食

米山英明

洋食

大和田敏嗣

和食

倉持英司

中華

伴敏嗣

洋食

織田雄太

中華

319 of 440

スプレッドシート実践 その2

(データをまとめて複数セルに出力する)

320 of 440

複数の値を入力する実験

複数の値実験」というシートを追加してください。

下記のような出力をするプログラムを作りたいとします。

321 of 440

スクリプトファイルを追加してください

ファイル名は「複数の値実験」にしてください。

322 of 440

これでもやりたいことは実現できる

function copySomeValue() {� var ss= SpreadsheetApp.getActiveSpreadsheet();� var sheet = ss.getSheetByName('複数の値実験');� � sheet.getRange('A1').setValue('あああ');� sheet.getRange('B1').setValue('いいい');� sheet.getRange('C1').setValue('ううう');� sheet.getRange('A2').setValue('えええ');� sheet.getRange('B2').setValue('おおお');� sheet.getRange('C2').setValue('かかか');�}

323 of 440

だけど問題があります。

function copySomeValue() {� var ss= SpreadsheetApp.getActiveSpreadsheet();� var sheet = ss.getSheetByName('複数の値実験');� � sheet.getRange('A1').setValue('あああ');� sheet.getRange('B1').setValue('いいい');� sheet.getRange('C1').setValue('ううう');� sheet.getRange('A2').setValue('えええ');� sheet.getRange('B2').setValue('おおお');� sheet.getRange('C2').setValue('かかか');�}�

SSに対して

アクセスしている

324 of 440

どゆこと?

SSとGASは住んでる世界が違うのです。

世界をまたぐには「コスト(時間)」がかかるのです。

function copySomeValue() {� var ss= SpreadsheetApp.getActiveSpreadsheet();� var sheet = ss.getSheetByName('複数の値実験');� � sheet.getRange('A1').setValue('あああ');� sheet.getRange('B1').setValue('いいい');� sheet.getRange('C1').setValue('ううう');� sheet.getRange('A2').setValue('えええ');� sheet.getRange('B2').setValue('おおお');� sheet.getRange('C2').setValue('かかか');�}

(getRangeしに行く+setValueしに行く) ✕ 6回 = 12回のアクセス

→ 時間がかかる

スプレッドシート界

GAS界

325 of 440

実行速度の比較の参考はここ

Google Apps Scriptのスプレッドシート読み書きを格段に高速化をする方法

https://tonari-it.com/gas-spreadsheet-speedup/

21秒かかったスクリプトが0.4秒になった例

326 of 440

GASには制限があるのです。

詳細はここ https://developers.google.com/apps-script/guides/services/quotas

実務上で一番問題になるのが「実行時間の上限が6分まで」という制限。

これを超えるとプログラムが途中終了されます。

→よって、実行時間は短いほうがいい。

327 of 440

一度に書き出す例 (コピーして実行してみよう)

function copySomeValue2() {� var ss= SpreadsheetApp.getActiveSpreadsheet();� var sheet = ss.getSheetByName('複数の値実験');� � var output = [� ['あああ','いいい','ううう'],� ['えええ','おおお','かかか']� ];� � sheet.getRange('A1:C2').setValues(output);�}

328 of 440

ポイント1:データをニ次元配列で作成する

function copySomeValue2() {� var ss= SpreadsheetApp.getActiveSpreadsheet();� var sheet = ss.getSheetByName('複数の値実験');� � var output = [� ['あああ','いいい','ううう'],� ['えええ','おおお','かかか']� ];� � sheet.getRange('A1:C2').setValues(output);�}

出力したいデータたちを

二次元配列で表現する

329 of 440

ポイント2:出力範囲を指定してsetValues

function copySomeValue2() {� var ss= SpreadsheetApp.getActiveSpreadsheet();� var sheet = ss.getSheetByName('複数の値実験');� � var output = [� ['あああ','いいい','ううう'],� ['えええ','おおお','かかか']� ];� � sheet.getRange('A1:C2').setValues(output);�}

出力範囲を正確に指定する

setValuesに二次元配列を渡す

330 of 440

(ハマリポイント) データ数は揃える必要がある!

[

['aa', 'bb', 'cc'],

['dd', 'ee', '']

]

最大の列数にあわせる

331 of 440

つまり、セルに書き出したいデータは

始めから2次元配列の形で用意しておくと

処理がラク!

332 of 440

スプレッドシート実践 その3

(行の末尾に追加したい)

333 of 440

さっきの続き

データは随時追加されていきます。

その時点の「一番下に追加したい」というニーズ、あるよねー。

こうかもしれないし

こうかもしれない

一番下に追加したい

334 of 440

例えばこうする

function copySomeValue3() {� var ss= SpreadsheetApp.getActiveSpreadsheet();� var sheet = ss.getSheetByName('複数の値実験');� � var output = [� ['AAA','BBB','CCC'],� ['DDD','EEE','FFF']� ];� � // シートに存在する一番最後の行数を取得できる� var lastRow = sheet.getLastRow();� � var fromRow = lastRow + 1; // 最終行の次の行から� var toRow = lastRow + output.length; // 最終行+貼り付けたいデータの行数� � // 範囲を指定して出力� sheet.getRange('A' + fromRow + ':C' + toRow).setValues(output);�}

実行結果

335 of 440

最終行の取得

function copySomeValue3() {� var ss= SpreadsheetApp.getActiveSpreadsheet();� var sheet = ss.getSheetByName('複数の値実験');� � var output = [� ['AAA','BBB','CCC'],� ['DDD','EEE','FFF']� ];� � // シートに存在する一番最後の行数を取得できる� var lastRow = sheet.getLastRow();� � var fromRow = lastRow + 1; // 最終行の次の行から� var toRow = lastRow + output.length; // 最終行+貼り付けたいデータの行数� � // 範囲を指定して出力� sheet.getRange('A' + fromRow + ':C' + toRow).setValues(output);�}

ココがポイント

336 of 440

出力範囲を指定する

function copySomeValue3() {� var ss= SpreadsheetApp.getActiveSpreadsheet();� var sheet = ss.getSheetByName('複数の値実験');� � var output = [� ['AAA','BBB','CCC'],� ['DDD','EEE','FFF']� ];� � // シートに存在する一番最後の行数を取得できる� var lastRow = sheet.getLastRow();� � var fromRow = lastRow + 1; // 最終行の次の行から� var toRow = lastRow + output.length; // 最終行+貼り付けたいデータの行数� � // 範囲を指定して出力� sheet.getRange('A' + fromRow + ':C' + toRow).setValues(output);�}

出力する「行数」を指定

(最終行の次なので +1 してる)

337 of 440

出力する

function copySomeValue3() {� var ss= SpreadsheetApp.getActiveSpreadsheet();� var sheet = ss.getSheetByName('複数の値実験');� � var output = [� ['AAA','BBB','CCC'],� ['DDD','EEE','FFF']� ];� � // シートに存在する一番最後の行数を取得できる� var lastRow = sheet.getLastRow();� � var fromRow = lastRow + 1; // 最終行の次の行から� var toRow = lastRow + output.length; // 最終行+貼り付けたいデータの行数� // 範囲を指定して出力� sheet.getRange('A' + fromRow + ':C' + toRow).setValues(output);�}

ここはただの文字列連結です

‘A5:C6’ みたいな文字列をつくる

338 of 440

スプレッドシート課題 (必修)

(別シートに出力する課題)

339 of 440

別のSSのシートにコピーする

「スプレッドシートA」のシート1から

「スプレッドシートB」のシート2に

「複数の値を一度にコピーする」方法を紹介します。

1)いま使っているSSに「全体シート」を追加してください。

2)自分のフォルダの中に「新しいSS」を作成して

「自チームシート」を作成してください。

340 of 440

こうなります

元のSSにシート追加

新しいSSを作成

341 of 440

使うデータはこれをコピーしてください

全体シート

予算

結果

部署A

収入

支出

利益

部署B

収入

支出

利益

部署C

収入

支出

利益

全社

収入

0

0

支出

0

0

利益

0

0

自分のチームのシート

予算

結果

収入の部

収入の内訳A

100000

120000

収入の内訳B

50000

30000

収入の内訳C

30000

18000

収入合計

180000

168000

支出の分

支出の内訳A

80000

40000

支出の内訳B

2000

5000

支出の内訳C

70000

46000

支出合計

152000

91000

利益

利益合計

28000

77000

342 of 440

やりたいことはこれ(自チーム=部署Bとする)

全体シート

予算

結果

部署A

収入

支出

利益

部署B

収入

支出

利益

部署C

収入

支出

利益

全社

収入

0

0

支出

0

0

利益

0

0

自分のチームのシート

予算

結果

収入の部

収入の内訳A

100000

120000

収入の内訳B

50000

30000

収入の内訳C

30000

18000

収入合計

180000

168000

支出の分

支出の内訳A

80000

40000

支出の内訳B

2000

5000

支出の内訳C

70000

46000

支出合計

152000

91000

利益

利益合計

28000

77000

343 of 440

「自チーム」のSSにスクリプトを追加します

「自チーム」のSSの値を集計し、全体のSSにコピーしに行く、をやります。

自チームのSSにスクリプトを追加してください。

プロジェクト名は「SS間コピー」で。

関数名は「copyToAllSheet」で。

SS間コピー

344 of 440

ここから課題

下記の続きを書いて、部署Bの情報を全体シートに記入できるようにしなさい

function copyToAllSheet() {� var myTeamSS = SpreadsheetApp.getActiveSpreadsheet();� var mySheet = myTeamSS.getSheetByName('自チームシート');� � var allSS = SpreadsheetApp.openById('xxxxx下記の調べ方参照 xxxxx');� var allSheet = allSS.getSheetByName('全体シート');�

// ここからプログラムを書く��}

345 of 440

今回の新しいこと

1つのプログラムの中で、複数のスプレッドシートを使う。

function copyToAllSheet() {� var myTeamSS = SpreadsheetApp.getActiveSpreadsheet();� var mySheet = myTeamSS.getSheetByName('自チームシート');� � var allSS = SpreadsheetApp.openById('xxxxx下記の調べ方参照 xxxxx');� var allSheet = allSS.getSheetByName('全体シート');�� // 自チームシートからA1の値を取り出して(A1に何か入力しておく)� var myData = mySheet.getRange("A1").getValue();� � // 全体シートのF1に書き出す� allSheet.getRange("F1").setValue(myData);�}

346 of 440

処理の流れイメージ

全体シート

予算

結果

部署A

収入

支出

利益

部署B

収入

支出

利益

部署C

収入

支出

利益

全社

収入

0

0

支出

0

0

利益

0

0

自分のチームのシート

予算

結果

収入の部

収入の内訳A

100000

120000

収入の内訳B

50000

30000

収入の内訳C

30000

18000

収入合計

180000

168000

支出の分

支出の内訳A

80000

40000

支出の内訳B

2000

5000

支出の内訳C

70000

46000

支出合計

152000

91000

利益

利益合計

28000

77000

output = [� [ '180000', '168000'],� [ '152000', '91000'],� [ '28000', '77000']�]

(1) 1つの配列にまとめる

(2) setValuesする

347 of 440

(任意課題) 応募者の中から抽選で10名に商品が当たる

新しいシートを作成して、シート名を「抽選」にしてください。

左記のように、「ID、名前」のダミーデータを200人以上作ってください。

(ダミーデータは 疑似個人情報生成 を利用しました)

応募者の中からランダムで10人の「当選」を決める

当選者のC列に「当」って出力する

(過去にやった「おみくじ」を参考に!)

348 of 440

Slack連携

349 of 440

新しいスクリプトファイルを作成

名前を

「slack通知」

にしてください

(全体シートのほうに)

350 of 440

Slack連携の手順

【初心者向け】GASを使ってSlackへ自動通知

↑ここがわかりやすいです。

手順としては

  • Slack側に Incoming WebHooks を設定する。
    • チャネルを指定して、外からそのチャネルにメッセージを送るためのURLが発行される(slackから見るとincomming)
    • このURLが漏洩すると誰でもこのチャンネルにメッセージを送信できるので注意!
  • GASから1で設定したURLにメッセージを送る
    • その際に「決まった形」があるのでそれに合わせる(コピペでいい)

これだけ。

351 of 440

Slack連携の手順

【初心者向け】GASを使ってSlackへ自動通知

↑ここがわかりやすいです。

手順としては

  • Slack側に Incoming WebHooks を設定する。
    • チャネルを指定して、外からそのチャネルにメッセージを送るためのURLが発行される(slackから見るとincomming)
    • このURLが漏洩すると誰でもこのチャンネルにメッセージを送信できるので注意!
  • GASから1で設定したURLにメッセージを送る
    • その際に「決まった形」があるのでそれに合わせる(コピペでいい)

これだけ。

レクチャではすでに設定をしておきました

352 of 440

Slackに通知する関数のコード

function notifyToSlack() {� // ↓このURLは #general-gas に送るためのURL。� var postUrl = 'https://hooks.slack.com/services/xxxxxxxx/xxxxxxxxxxxxxxxxxxx';� � // ↓ここは好きにしてみて� var username = 'xxx'; // 通知時に表示されるユーザー名� var icon = ':sunny:'; // 通知時に表示されるアイコン(※)� var message = 'slack通知のテストです'; // 投稿メッセージ� � // これより下は「お約束」なのでこのままでOK� var jsonData = {� "username" : username,� "icon_emoji": icon,� "text" : message� };� var payload = JSON.stringify(jsonData);�� var options = {� "method" : "post",� "contentType" : "application/json",� "payload" : payload� };�� UrlFetchApp.fetch(postUrl, options);�}

(※) アイコンはここらへんから選ぶ

https://www.webpagefx.com/tools/emoji-cheat-sheet/

青字の部分を変更して実行してみよう

incoming webhooks のURL

353 of 440

実際はこんな感じで使う

function myFunction() {�� // ここで何か処理をして� // slackに送りたいメッセージを作成する�� var message = 'あいうえお';� � // slackへの送信はこの関数に任せる� notifyToSlack(message);�}

function notifyToSlack(message) {� // ↓このURLは #general-gas に送るためのURL� var postUrl = 'https://hooks.slack.com/services/xxxxxxxxxxx/xxxxxxxx;� � // ↓ここは好きにしてみて� var username = 'xxx'; // 通知時に表示されるユーザー名� var icon = ':sunny:'; // 通知時に表示されるアイコン(※)

//↓messageは引数でもらうのでこの行は不要� //var message = 'slack通知のテストです';

� // これより下は「お約束」なのでこのままでOK� var jsonData = {� "username" : username,� "icon_emoji": icon,� "text" : message� };� var payload = JSON.stringify(jsonData);�� var options = {� "method" : "post",� "contentType" : "application/json",� "payload" : payload� };�� UrlFetchApp.fetch(postUrl, options);�}

こっちの関数でなにかさせる

354 of 440

Googleフォーム

355 of 440

GoogleフォームでGASといえば圧倒的にこれ!

フォームに送信があったらメールで通知してほしい

356 of 440

...でもそういう機能がついたみたいデス

昔はこんなん無かったよ

357 of 440

でもslack通知はデフォ機能じゃできない!→やろう

自分のフォルダにフォームを作成

「新規 → Googleフォーム」

※このGASはフォームに紐付きます

358 of 440

適当に質問つくってください

1.質問をつくって

3.スクリプトエディタを開く

2.ここから

359 of 440

ひとまずコピペする

function submitForm(e){� var title = e.source.getTitle();� var items = e.response.getItemResponses();� var message = 'フォーム[' + title + ']に回答がありました\n';�� for (var i = 0; i < items.length; i++) {� var item = items[i];� var question = item.getItem().getTitle();� var answer = item.getResponse();� message += (i + 1).toString() + '. ' + question + ': ' + answer + '\n';� }� notifyToSlack(message);�}��function notifyToSlack(message) {� // ↓このURLは #general-gas に送るためのURL� var postUrl = 'https://hooks.slack.com/services/xxxxxx/xxxxx;� � // ↓ここは好きにしてみて� var username = 'xxxx'; // 通知時に表示されるユーザー名� var icon = ':sunny:'; // 通知時に表示されるアイコン� � // これより下は「お約束」なのでこのままでOK� var jsonData = {� "username" : username,� "icon_emoji": icon,� "text" : message� };� var payload = JSON.stringify(jsonData);�� var options = {� "method" : "post",� "contentType" : "application/json",� "payload" : payload� };�� UrlFetchApp.fetch(postUrl, options);�}�

ここだけ変えてみよう

360 of 440

トリガーが必須

トリガーを設定することで、このGASがいつ実行されるか指定できます

submitForm

361 of 440

「プレビュー」→ 回答してみよう

362 of 440

コードの解説

function submitForm(e){� var title = e.source.getTitle();� var items = e.response.getItemResponses();� var message = 'フォーム[' + title + ']に回答がありました\n';�� for (var i = 0; i < items.length; i++) {� var item = items[i];� var question = item.getItem().getTitle();� var answer = item.getResponse();� message += (i + 1).toString() + '. ' + question + ': ' + answer + '\n';� }� notifyToSlack(message);�}�

e(多分eventの略)の中に

送信されたフォームの情報が詰まってる

こうすることで「質問」「回答」のペアが、

設定された数の分だけ取得できる

出力するメッセージを作る

363 of 440

GmailをGASで操作する

364 of 440

新しいスクリプトファイルを作成

名前を

「Gmail」

にしてください

(スプレッドシートの方で)

365 of 440

Gmailサービスの構造

  • 一通の「メール」をGmailサービスでは「Message」と呼ぶ
  • メッセージのやり取り(返信)をまとめたものを「Thread」と呼ぶ

GmailApp

 └Thread

   └ Message

      └ Attachment

366 of 440

Messageを取り出す時

GmailApp

 └Thread

   └ Message

      └ Attachment

1.Threadを検索する

2.1のThreadの中からMessageを取り出す

367 of 440

Thread検索の前に、Gmail検索使いこなしてる?

ここをうまく使おう。

例えば

  • 件名に「サンプル」という文字が含まれていて
  • 今日から20日以内に届いたメール

subject:サンプル newer_than:20d

368 of 440

これをGASで書くと (コピーして実行してみる)

function searchMessage() {� var query = 'subject: サンプル newer_than:10d';� var threads = GmailApp.search(query);� var messages = GmailApp.getMessagesForThreads(threads);� � messages.forEach(function(thread) {� thread.forEach(function(message) {� Logger.log('----------------------');� Logger.log(message.getSubject());� Logger.log(message.getFrom());� Logger.log(message.getPlainBody());� });� });�}

HITしたスレッドの中から

メッセージを取り出せる

queryの条件でメール検索

369 of 440

最初の一通だけ取得したい

function searchMessage() {� var query = 'subject: サンプル newer_than:10d';� var threads = GmailApp.search(query);� var messages = GmailApp.getMessagesForThreads(threads);�messages.forEach(function(thread) {� thread.forEach(function(message) {� Logger.log('----------------------');� Logger.log(message.getSubject());� Logger.log(message.getFrom());� Logger.log(message.getPlainBody());� });� });�}

これだと返信を含めてすべてのメールを取り出すことになる。

各スレッドの1通目だけほしいことがあるよね。

(外部からの通知メールとか)

370 of 440

最初の一通だけ取得したい

function searchMessage2() {� var query = 'subject: サンプル newer_than:10d';� var threads = GmailApp.search(query);� var messages = GmailApp.getMessagesForThreads(threads);�� messages.forEach(function(thread) {� var message = thread[0];� Logger.log(message.getSubject());� Logger.log(message.getFrom());� Logger.log(message.getPlainBody());� });�}

thread[0] が最初のメッセージです

371 of 440

Gmailでもっといろんなことがしたい人は

【GAS】Gmailに送られた過去のメールから特定条件のメールを検索して取得するhttps://tonari-it.com/gas-gmail-search-thread/

372 of 440

実務で使うパターン

  • 特定のFromアドレスから不定期にメールが届く

  • メール本文に特定の文字列が存在したらslack通知したい

  • (過去に通知したものはいらない)

373 of 440

実務で使うパターン (任意課題)

  • 特定のFromアドレスから不定期にメールが届く
    • GASの「トリガー」を使って、定期的に(1日1回とか)メールチェックする

  • メール本文に特定の文字列が存在したらslack通知したい
    • 本文にキーワードが含まれるかチェック。正規表現。
    • 本文は上記コードの query に文字列を書けばOK

  • 過去に通知したものはいらない
    • 通知したらSSに記録。それと比較して新しいものだけが通知対象にする
    • (検索条件で newer_than:1d にして、トリガーで1日1回実行する、もあり得るけど、「厳密さ」は保証されていないので、必要なら自分で作る)

374 of 440

実務で使うパターン (任意課題) ヒント

  • 特定のFromアドレスから不定期にメールが届く
  • メール本文に特定の文字列が存在したらslack通知したい

  • 過去に通知したものはいらない
    • 各スレッドのfirstMessageの中から、受信時刻が最新のものの受信時刻をSSに書き出す
    • 次回以降はこの時刻よりも新しいものだけをチェックする
    • 新しいものがあったら「最新受信時刻」を上書きする

もっといいロジックがありそう

375 of 440

他にもgoogleのサービスはある

ここまでで

  • スプレッドシート
  • フォーム
  • Gmail

を扱いましたが、他にも業務で使いそうな

  • Googleドライブ
  • Googleカレンダー
  • Googleドキュメント

...もGASで扱えます。

376 of 440

正規表現

(文字列を扱う時に役に立ちます)

377 of 440

新しいスクリプトファイルを作成

名前を

「正規表現」

にしてください

378 of 440

正規表現とは?

Regular Expression 日本語で「正規表現

いくつかの文字列を一つの形式で表現するための表現方法

例1: 郵便番号を表現するパターン

  • 3つの数字 + ハイフン + 4つの数字
  • 7つの数字

\d{3}-?\d{4}

379 of 440

正規表現とは?

Regular Expression 日本語で「正規表現

いくつかの文字列を一つの形式で表現するための表現方法

例1: 郵便番号を表現するパターン

  • 3つの数字 + ハイフン + 4つの数字
  • 7つの数字

\d{3}-?\d{4}

\d 半角数字

{n} 直前の文字をn回繰り返す

? 直前の文字が0回か1回ある

今は「へぇー...」

くらいでOK!

380 of 440

どんな時に使うか?

例)文字列の中に電話番号が入っていたら、それを*****に置き換える。

  • 「正規表現」のシートを新規作成してください
  • A1セルに下記の文章をコピペしてください。

-------------------------------------

こんにちわ。�私の電話番号を教えますね。��080-0000-0000��です。よろしくー。

381 of 440

コピペして実行(電話番号マスキングサンプル)

function regexpSample() {� var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("正規表現");� var text = sheet.getRange("A1").getValue();� � var reg = /\d{3}-?\d{4}-?\d{4}/;� � var output = text.replace(reg, '*****');� � sheet.getRange('A3').setValue(output);�}�

382 of 440

コード解説

function regexpSample() {� var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("正規表現");� var text = sheet.getRange("A1").getValue();� � var reg = /\d{3}-?\d{4}-?\d{4}/;� � var output = text.replace(reg, '*****');� � sheet.getRange('A3').setValue(output);�}�

正規表現(パターン)を定義してあげる

/ と / で挟むのがルール

383 of 440

コード解説

function regexpSample() {� var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("正規表現");� var text = sheet.getRange("A1").getValue();� � var reg = /\d{3}-?\d{3,4}-?\d{4}/;� � var output = text.replace(reg, '*****');� � sheet.getRange('A3').setValue(output);�}�

text に対して

reg とマッチする文字列を

***** に置き換えろ(replace)

という命令

384 of 440

電話番号を複数書いてみると。。。(゜A゜ノ)ノ

こんにちわ。�私の電話番号を教えますね。��080-0000-0000�090-1111-1111��です。よろしくー。

2つ目以降は置換されない

385 of 440

コピペして実行

function regexpSample() {� var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("正規表現");� var text = sheet.getRange("A1").getValue();� � var reg = /\d{3}-?\d{3,4}-?\d{4}/g;� � var output = text.replace(reg, '*****');� � sheet.getRange('A3').setValue(output);�}�

「フラグ」をつけることができる

g = global (すべてのマッチを探すフラグ)

この指定がないと、最初にマッチしたものだけが対象になる

386 of 440

他にもこんな使い方1

  • NGワードフィルタ
    • 複数のNGワードを定義する
    • 複数の投稿がある
    • それぞれの投稿にNGワードが含まれるかどうかを判定するプログラム
    • (→ある文字列に、ワードAまたはワードBまたはワードC...が含まれるか、のチェック)

387 of 440

他にもこんな使い方2

1.Gmailで受信したメール

ータイトル

ー見出し

ーURL

を1組にして複数個切り出してスプレッドシートに自動で書き出す。とか。

388 of 440

正規表現にはこれが便利

概要を知りたい

自分が書いた正規表現がどういう意味なのか、何にマッチするのか知りたい

JavascriptのRegExpについて知りたい

389 of 440

Moment(日付)

390 of 440

(ライブラリ) Moment

日付を扱う組み込みオブジェクトとして「Dateオブジェクト」が用意されている。

だけどこれがちょっと使いにくい。

日付・時刻をもっと簡単に扱えるように「Moment.jsライブラリ」を作ってくれた人がいる。

それを使うと、Dateを使うよりラクに日付・時刻を扱えるので、こっちを使おう。

https://momentjs.com/

が公式

391 of 440

Momentライブラリを追加する

https://tonari-it.com/gas-moment-js-moment/

392 of 440

Momentライブラリを追加する

https://tonari-it.com/gas-moment-js-moment/

プロジェクトキー:MHMchiX6c1bwSqGM1PZiW_PxhMjh3Sh48

393 of 440

日付の計算をしてみます

「日付」というシートを作って、下記の表を作ってください。

(期限日は自由に日付をいれてください)

今日から期限日まで、何日あるのか、

を計算するプログラムを書きます。

例えば3日前にリマインドメールを送る

みたいな使い方。

394 of 440

Momentの使い方

とりあえずはここ

https://tonari-it.com/gas-moment-add-subtract/

詳細はここ

https://www.yoheim.net/blog.php?q=20180201

オフィシャルはここ

https://momentjs.com/docs/#/use-it/

タイムゾーンについて...

(GASでは使えないのかな?グローバルなアプリを使う場合は同時刻でもそのTZで何時なのか、は大事)

https://momentjs.com/timezone/

395 of 440

Moment (コピペして実行してみよう)

function dateSample() {� var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("日付");� var deadline_str = sheet.getRange("B2").getValue(); //日付の「文字列」が取得できる� var deadline_obj = Moment.moment(deadline_str); // Moment.moment(日付文字列)でMomentオブジェクトができる� � var today_obj = Moment.moment(); // 引数なしで「今現在」を表すMomentオブジェクトができる� � // deadline - today の差を 日(days) で出す (時間とか分とか秒とかでもだせる)� var term = deadline_obj.diff(today_obj, 'days');� � if (term <= 3) {� GmailApp.sendEmail(� 'xxxx@xxxx.co.jp',� '[リマインダ]期限が近いタスクがあります',� '期限が迫っているタスクがあるので確認よろしく!');� }�}

自分のメアド

396 of 440

Moment (コピペして実行してみよう)

function dateSample() {� var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("日付");� var deadline_str = sheet.getRange("B2").getValue(); //日付の「文字列」が取得できる� var deadline_obj = Moment.moment(deadline_str); // Moment.moment(日付文字列)でMomentオブジェクトができる� � var today_obj = Moment.moment(); // 引数なしで「今現在」を表すMomentオブジェクトができる� � // deadline - today の差を 日(days) で出す (時間とか分とか秒とかでもだせる)� var term = deadline_obj.diff(today_obj, 'days');� � if (term <= 3) {� GmailApp.sendEmail(� 'xxxx@xxxx.co.jp',� '[リマインダ]期限が近いタスクがあります',� '期限が迫っているタスクがあります。\nhttp://xxxx \nを確認してください.');� }�}

Moment.moment(‘2018/4/1’)

で、この日付を意味するオブジェクトができる。

Moment.moment()

で、「現時刻」を意味するオブジェクトができる。

397 of 440

Moment (コピペして実行してみよう)

function dateSample() {� var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("日付");� var deadline_str = sheet.getRange("B2").getValue(); //日付の「文字列」が取得できる� var deadline_obj = Moment.moment(deadline_str); // Moment.moment(日付文字列)でMomentオブジェクトができる� � var today_obj = Moment.moment(); // 引数なしで「今現在」を表すMomentオブジェクトができる� � // deadline - today の差を 日(days) で出す (時間とか分とか秒とかでもだせる)� var term = deadline_obj.diff(today_obj, 'days');� � if (term <= 3) {� GmailApp.sendEmail(� 'xxxx@xxxx.co.jp',� '[リマインダ]期限が近いタスクがあります',� '期限が迫っているタスクがあります。\nhttp://xxxx \nを確認してください.');� }�}

deadline_obj から today_obj を引いた時間を days(日)単位で表す

もっといろんな使い方ができます。

「Moment.js」で検索!!

398 of 440

UrlFetch

(資料未完成)

399 of 440

外部サイトにHTTPリクエストを送ることができます!

APIを使ってみようと思ったのですが、資料の準備が間に合いませんでした。

【Google Apps Script】天気予報をWeb APIで取得する方法

栄養価を算出するWeb APIをGASで作成しました!

↑このあたりをやってみよう!

400 of 440

組み込みオブジェクト

  • 変数…箱と中身
  • 算術演算子…数字の計算ができる
  • 文字列結合…文字列をくっつける
  • Javascriptのルール…コーディングする上でのルール
  • 条件分岐…もし●●だったら☓☓をする
  • 配列…大きな箱に複数の箱を入れられる
  • ループ…処理の繰り返し
  • 関数…処理をひとまとめにしておく
  • 組み込みオブジェクト…始めから用意されている「道具」

背景がグレーのスライドは

自分が必要になったときに「こういうものがあるんだ」「こんなワードで調べられるんだ」

を知っておいてもらえればOK。あとは実務で必要になるし。

401 of 440

新しいスクリプトファイルを作成

名前を

「組み込みオブジェクト」

にしてください

402 of 440

組み込み関数とは

「最初から用意されている関数」のこと。

よく使われる道具がすでに用意されている、ということ。

よく使うやつ

  • String: 文字列の扱い(置き換えたり、切り出したり、分けたり)
  • Date: 日付と時刻 (現在時間の取得、今から何時間前/後など)
  • Array: スプレッドシートはいかに配列を使いこなすかが勝負。配列の処理 (要素の追加・削除、ソートしたり)

使わないかもしれないけど知っておけ、なやつ

  • Math: 数学的な計算をしてくれるやつ
  • Regexp: 正規表現

403 of 440

ここでは...

「使い方の調べ方」を覚えてください。

組み込み関数は膨大にあります。私も覚えてません。

「こんな関数あったな」とか「こういうことができる関数あるかな」を

自分で調べてコピペして使う、がキホンです!

例えば「Javascript String」で検索すると詳しく教えてくれるサイトがいっぱいある。注意点としては「新しい情報かどうか」(Javascriptも進化しているので古いと使えないモノがある)

404 of 440

String(文字列)

405 of 440

Stringに関すること (コピペして実行してみよう)

function stringObject1() {� var str = 'My name is Bob.';� � Logger.log(str.length); // 15 (文字数)� Logger.log(str.indexOf('is')); // 8 (isが始まるindexを返す)� Logger.log(str.slice(3, 7)); // name (index指定。後ろのindexの直前まで)�� // 置換はreplace� Logger.log(str.replace('Bob', 'Sakaimo'));

// ファイル名から拡張子を取り出すには?� var fileName = 'test.image.jpg';� Logger.log( fileName.slice( fileName.lastIndexOf('.')+1 ), fileName.length );�}

406 of 440

Stringに関すること (コピペして実行してみよう)

function stringObject1() {� var str = 'My name is Bob.';� � Logger.log(str.length);� Logger.log(str.indexOf('is'));� Logger.log(str.slice(3, 7));�� // 置換はreplace� Logger.log(str.replace('Bob', 'Sakaimo'));

// ファイル名から拡張子を取り出すには?� var fileName = 'test.image.jpg';� Logger.log( fileName.slice( fileName.lastIndexOf('.')+1 ), fileName.length );�}

文字数を返す

()内の文字があるインデックスを返す

文字列を切り取る

BobをSakaimoに置き換える

()内の文字が最後に出てくるインデックスを返す

407 of 440

覚えておくことはこれ

細かいところは覚えなくていい。

だけど「文字列を操作する関数」としてどんなものがあるのか、は覚えておく。

文字列に対して

  • 文字を足す
  • 文字を取る
  • 文字を置き換える
  • 文字を分ける

をしたい → 調べる

408 of 440

調べ方の実演 indexOf

まずは「構文(書き方のルール)」を見る

「引数」と「戻り値」を確認

409 of 440

サンプル見ちゃうのが早いよね

410 of 440

「使い方」「やりたいこと」で調べる

「Javascript indexOf 使い方」とか、

「javascript 文字列 切り出す」とか、

「Javascript 文字 置換」とか。

わからなかったら検索する。

検索の仕方を知ることと、使い方の読み方が大事。

初心者はリファレンスでくじけるけど慣れてないだけ。リファレンスは味方です.

411 of 440

例えば。。。

ある文字列の中に、特定の文字列が含まれるかどうかを調べたい。

<サンプル文章>

日本国民は、正当に選挙された国会における代表者を通じて行動し、われらとわれらの子孫のために、諸国民との協和による成果と、わが国全土にわたつて自由のもたらす恵沢を確保し、政府の行為によつて再び戦争の惨禍が起ることのないやうにすることを決意し、ここに主権が国民に存することを宣言し、この憲法を確定する。

この文章の中に「自由」という文字列が存在するかどうか、を調べるプログラムを作りたい。

412 of 440

Google先生に聞いちゃうと早いよね

413 of 440

indexOfでできるらしい

function stringObject2() {�� var text = '日本国民は、正当に選挙された国会における代表者を通じて行動し、われらとわれらの子孫のために、諸国民との協和による成果と、わが国全土にわたつて自由のもたらす恵沢を確保し、政府の行為によつて再び戦争の惨禍が起ることのないやうにすることを決意し、ここに主権が国民に存することを宣言し、この憲法を確定する。';� var word = '自由';� � if (text.indexOf(word) !== 1) { //含まれていない場合に-1を返す、を利用する� Logger.log(word + 'が含まれている');� } else {� Logger.log(word + 'が含まれていない');� }�}

414 of 440

Array(配列)

415 of 440

Array (コピペして実行してみよう)

function arraySample1() {� var characters = ['悟空', 'ピッコロ', 'クリリン', 'ベジータ'];� � Logger.log(characters.length);� Logger.log(characters.toString());� Logger.log(characters.join('|'));� Logger.log(characters.concat(['ヤムチャ','亀仙人']));� Logger.log(characters.slice(1,3));� Logger.log(characters.indexOf('クリリン'));�}

注意点:length は () がつかない。関数じゃなくプロパティだから。

416 of 440

Array 配列を変更する

function arraySample2() {� var characters = ['悟空', 'ピッコロ', 'クリリン', 'ベジータ'];� � characters.push('魔神ブウ'); //末尾に追加� Logger.log(characters);� � characters.unshift('天津飯'); //先頭に追加� Logger.log(characters);� � characters.reverse(); // 並びを逆にする� Logger.log(characters);� � characters.sort(); // ソートする。何の順? ←調べてみよう� Logger.log(characters);�}�

417 of 440

配列といえば「要素をとりだして処理する」

// 要素一つずつを取り出して、関数を実行する(コールバック関数と呼ぶ)�// 関数の中で要素を使えるように「仮引数」を用意する(名前は自由)�function arraySample3() {� var characters = ['悟空', 'ピッコロ', 'クリリン', 'ベジータ'];� � characters.forEach(function(name, index, array) {� Logger.log(index + ': Hello ' + name +'!');� });�}

418 of 440

forEach 解説

// 要素一つずつを取り出して、関数を実行する(コールバック関数と呼ぶ)�// 関数の中で要素を使えるように「仮引数」を用意する(名前は自由)�function arraySample3() {� var characters = ['悟空', 'ピッコロ', 'クリリン', 'ベジータ'];� � characters.forEach(function(name, index, array) {� Logger.log(index + ': Hello ' + name +'!');� });�}

characters配列の「要素一つずつ」に対して、function() を実行するよ。

関数の中では、要素の値は name, インデックスは index, 元の配列は array

という変数で扱うよ。ということ。(仮引数は自分でつけていい)

419 of 440

map コールバック関数の戻り値で新たな配列を生成

function arraySample4() {� var characters = ['悟空', 'ピッコロ', 'クリリン', 'ベジータ'];� � var new_array = characters.map(function(name, index, array) {� return name + 'さん';� });� � Logger.log(new_array); // 新しく作った配列� Logger.log(characters); // 元の配列の中身は変化なし�}�

characters配列の「要素一つずつ」に対して、

function() を実行した結果で、新たな配列を作って、new_array に代入するよ。

他にも every, some, filter という「反復メソッド」が用意されてます。

420 of 440

Math(数学的処理)

421 of 440

Math (コピペして実行してみよう)

function mathSample() {� Logger.log(Math.ceil(10.5)); //小数点以下を切り上げ� Logger.log(Math.floor(10.5)); //小数点以下を切り捨て� Logger.log(Math.round(10.5)); //小数以下を四捨五入して「整数」にする�}

ログに出力される小数点は「無かったこと」にしてください。

スクリプトエディタの仕様で、内部的には「整数」になってる

422 of 440

Math (コピペして実行してみよう)

function mathSample() {� Logger.log(Math.ceil(10.5)); //小数点以下を切り上げ� Logger.log(Math.floor(10.5)); //小数点以下を切り捨て� Logger.log(Math.round(10.5)); //小数以下を四捨五入して「整数」にする�}

これ、困るよね!?

例えば 1÷7 = 0.142857142857…(142857の循環小数)

を 小数第三位で四捨五入して「0.14」にする、ができない。

423 of 440

小数第三位で四捨五入、のサンプル

Math.round(x)の仕様

x の小数部分が、.5 以上(.5 を含む)の場合、その引数は、次に大きい整数に切り上げられます。

x の小数部分が、.5 未満(.5 を含まない)の場合、その引数は、次に小さい整数に切り下げられます

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Math/round

小数第三位で四捨五入する場合

0.142857142857...

↓ 100倍する

14.2857142857...

Math.round(14.2857142857...)

↓ roundされる

14

↓ 100分の1する

0.14

赤字部分が四捨五入される

//コードにするとこうなる

function roundSample() {� var num = 1/7;� var result = Math.round(num*100)/100;� Logger.log(result);�}

424 of 440

おみくじサンプル(再掲+解説)

function omikuji() {� var omikuji = ['大吉','中吉', '吉', '凶'];�� var x = Math.floor(Math.random() * 4);� Logger.log( omikuji[x] );�}

1.0以上1未満のランダムな小数を返す

2.引数として与えた数以下の

最大の整数を返します。

4倍するということは、

「0*4 = 0」 から「0.999….*4 = 4未満」

までの値になる

Math.floor(2.345) なら 2 になる

(小数点以下を切り捨てるということ)

425 of 440

他にもMath

くわしくは下記にあります。

(こゆのがあるんだな、ということを覚えておいて下さい)

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Math

426 of 440

レクチャーの最後に

427 of 440

残念ながらこれだけじゃ実現できない

ここに載っていること+自分で調べたことを

「組み合わせる」ことで

やりたいことを実現するフェーズに入ります。

428 of 440

プラモデルはパーツがあって、

設計書通りに組み立てたら、完成します。

429 of 440

プログラムはパーツがあって、

設計書通りに組み立てたら、完成する。。。

わけじゃない

ありもののパーツを見つけてくる。

いいパーツがなければ自分で作る。

組み立ての順番も自分で考える

430 of 440

プログラム初学者の2大「わからない」

  • 手順がわからない

→「人がその処理をしたらどういう順番で何をするか」を紙に書く

    • A1:D100 の範囲のセルを対象にする
    • 上から1行ずつ、B列のメールアドレスを見る
    • 特定のドメインだったらC列に「★」を入力する

  • プログラムに翻訳できない

→調べることで解決できることが多い

→言語の仕様や関数の使い方

なるべく「小さな」「単純な」処理に分解する

ここは知ってる/知らないの世界なので

「自分で調べる」「分かる人に聞く」

で解決できる

431 of 440

効率よくコードを書くために

「すでに用意されている便利な道具(関数や他人のコード)」をうまく使おう。

「自分で生み出すスキル」よりも、「あるものを使うスキル」の方が大事。

そのためには「何があるのかを調べるスキル」が大事

  • すでに用意されているものがあるのか?
  • あったとして、それをどうやって使うのか?
  • それは今でも使えるのか?(情報が古いこともある)

432 of 440

ここまではプログラミングの中のごく一部

  • Webプログラミングの中の一部
  • 「限られた範囲で」コンピューターと会話ができるようになった
  • 例えば、英語で法律の話をするにはもっと正確な、厳密な英語が必要になるし、スペイン語圏に行ったら言語を変えないとならない
  • Javascriptについて体系的に(だけどサクッと)学びたい人はドットインストールだ!(ここまでやってきた人にとってはすぐ理解できるはず)

433 of 440

その先に

434 of 440

コードが継続して利用され続けるために

  • 自分で書けると楽しいし嬉しいよね! → このモチベーション大事
  • じゃんじゃん効率化したいよね! → 当然だよね
  • 業務効率化するコードを量産していく → 効率が上がる
  • そのコードを前提に業務が設計される → 当然だよね

435 of 440

将来の問題点

  • 次に来る問題点(1)
    • 業務が変化し、コードを変更しなければならなくなった
    • そのコードを書いた人が退職した
    • それでも業務を続けなければならない
    • 想定外の使われ方をして動かなくなった�
  • 次に来る問題点(2)
    • データの量が多くなってきて時間がかかる、処理が遅くなる

436 of 440

将来の問題点

  • 次に来る問題点(1)
    • 業務が変化し、コードを変更しなければならなくなった
    • そのコードを書いた人が退職した
    • それでも業務を続けなければならない
    • 想定外の使われ方をして動かなくなった�
  • 次に来る問題点(2)
    • データの量が多くなってきて時間がかかる、処理が遅くなる

「自分だけがわかればいい」だと業務継続ができなくなる可能性が上がる

�「GASを書ける人が複数人いる+他の人が見ても理解できるコードである」

437 of 440

将来の問題点

  • 次に来る問題点(1)
    • 業務が変化し、コードを変更しなければならなくなった
    • そのコードを書いた人が退職した
    • それでも業務を続けなければならない
    • 想定外の使われ方をして動かなくなった�
  • 次に来る問題点(2)
    • データの量が多くなってきて時間がかかる、処理が遅くなる

結果は同じでも「効率のいい書き方」がある (ない場合もあるけど)�遅い場所を突き止めて、改善していく(パフォーマンス改善)

438 of 440

継続して使われ続けるための知識・ノウハウ

  • 読みやすいコードを書く
    • リーダブルコード(の要約) とても読みやすいし取り入れやすい
  • コード管理・コードレビュー
    • 複数人でコードを把握、管理する
  • 「保守・運用」
    • 継続して使われる→不具合が起こる→それに対応する、を行うだけのリソース確保
  • テスト・品質保証
    • プログラムが意図したように動くことをどうやって確認するか
    • 不具合が起こった時に気づけるような仕組みをつくるとか

439 of 440

卒業課題

440 of 440

卒業課題

レクチャーの最初に「(宿題2)何を効率化したいのか?を決めること」をおこなってもらいました。

そのままでもいいですし、レクチャを受けてやってみたいことが変わってもいいです。

どんな小さくでもいいので、自分の業務を効率化・自動化できるGASを書いてください。

「やった気になる」ではなく「実際に完成させる」までやることが大事です!