V8エンジン対応版の資料を公開しましたこれから学ぶ方はこちらで!
↓�https://docs.google.com/presentation/d/1B4av1gPS9xW4XVRqcih6R4Oe5nQabsm3AYO54Y9HDQ0/edit
ノンプログラマ向け
社内GASレクチャー
これは何か?
私(@sakaimo) が社内でおこなった、ノンプログラマ向けのGoogle Apps Script (GAS) のレクチャーの資料です。
営業やバックオフィス業務を行なっているメンバーが、GASが書けるようになったら業務の効率が上がるのでは?書けなくとも「こんなことができるのか」ってわかってもらえたら、そこから効率化のネタが見つかるのでは?との思いではじめました。
資料の中身について
実際のレクチャではこの資料を見ながら、私がホワイトボードに書いて説明したり、ライブコーディングしていくなどの補足要素があってこそ成り立つ部分もあったりします。
ですので、まったくの初学者がこのドキュメントを見たときに説明不足で「え?」ってなる箇所があるかもしれませんが、そゆことでご了承ください。
コメントはこちら(Qiita)の方にお願いします。
事前の宿題
(宿題1)「頭の体操」なので楽しくやってください!
アルゴロジック2
https://home.jeita.or.jp/is/highschool/algo/prm/index2.html
↑これの「順次処理」「繰り返し」「分岐処理」は必須。
(宿題2)何を効率化したいのか?を決めること
卒業課題にもなりますが、現時点で「GASで実現したいこと」を1つ以上挙げておいてください。
業務ではスプレッドシート、Gmail、GoogleDrive...を使うと思うのですが、
「毎回同じ操作してるな」とか「こゆの自動化できないのかな」っていうネタを出しておくこと!
(レクチャ受けておしまい、になりがちなので少しでも(数秒でも)自分の作業をラクにできた!というプログラムを作って、卒業となります)
→受講中に何ができるのかがわかってきて、課題を変えるってのもOKです。
事前宿題
赤枠内を
クリアしておいてください
事前準備
GoogleDriveにレクチャ用の「フォルダ」を作成してください。
その中にスプレッドシートなどを作っていきます。
GASのためのJavascript入門
社内レクチャ
目次②
はじめに
注意事項
このスライド上にいっぱいコードが出てきます。
各自のPCでもこのスライドを見えるようにしておいてください。
スライドのコードをコピペして実行してもらうこともあります。
レクチャでは下記の3画面を行ったり来たりします。
下記の「1と2」あるいは「2と3」を同時に見えるようにしておくと効率上がります。
レクチャーの対象者
プログラムできるようになると何が良いか
このレクチャーの「卒業試験」に合格すると
さらにその先に
上級
初級
そう。「卒業試験」あります。
わかったつもり、で終わらせないために。
自分の業務・作業が少しでもラクになるGASを作成する。
課題提出してもらいます。
レクチャーが終わるまでには課題を決めておいてください。
(どんな小さい効率化でもいいです)
今回扱わないもの
GoogleAppsScriptの紹介
GASでできること
...など (詳細! GoogleAppsScript完全入門 P12により引用)
<社内実例紹介>
ホントはここに社内事例があったのだけれど、いろいろあって公開できないので、別などこかで公開したいと思います。例としては
みたいな例です。
(GASに限らず)プログラム...って?
プログラミング言語って何?
コンピュータの中は0と1でできている(らしい)
https://style.nikkei.com/article/DGXKZO97458000Z10C16A2W12001?channel=DF210220171916
そのコンピュータに命令するための(人間がみてわかる)「言語」
機械がわかる
ように変換
人が見て
わかる表現
プログラムのキホン
「順次、分岐、反復」(アルゴロジックでやったやつ)
順次:上から順番に実行される
分岐:「条件」によって処理が変わる
反復:条件が満たされる限り、処理を繰り返す
...例えば右図は「人生フローチャート」
プログラムのキホン
「順次、分岐、反復」
順次:上から順番に実行される
分岐:「条件」によって処理が変わる
反復:条件が満たされる限り、処理を繰り返す
プログラムのキホン
「順次、分岐、反復」
順次:上から順番に実行される
分岐:「条件」によって処理が変わる
反復:条件が満たされる限り、処理を繰り返す
プログラムのキホン
「順次、分岐、反復」
順次:上から順番に実行される
分岐:「条件」によって処理が変わる
反復:条件が満たされる限り、処理を繰り返す
プログラムのキホン
「順次、分岐、反復」
順次:上から順番に実行される
分岐:「条件」によって処理が変わる
反復:条件が満たされる限り、処理を繰り返す
プログラミングは、これらの処理を
「プログラム言語」で表現する
機械は空気を読んでくれない
人間は空気、行間、暗黙の了解、を理解できる。機械はそゆのわからない。
例えば会話で「先週は毎日ランチにラーメン食べたよ」というのは、人間なら「先週の平日のランチがラーメンだったんだな」って解釈する場合もあるだろうけど、機械では「土日祝祭日も含めて先週の7日間のランチがラーメンだった」って解釈するし「先週」っていつ起算の7日間のことかもわからない。
→曖昧さをなくすのが大事
GASを書くデモをします
ライブコーディングするので
私の画面を眺めててください
フォルダ内にスプレッドシートを作成
ツール > スクリプトエディタ
やることは3つ
1.コードを書く
4.実行する
2.保存する
3.関数を選ぶ
初回だけ認証が必要
スプレッドシートの方に表示されているはず
これで「GASが動いている」ことが
確認できました!
コードの解説
function myFunction() {� Browser.msgBox('hello world');�}
Browser(画面)に、
msgBox(メッセージボックス)を出してね。
表示させるのは「hello world」ね。
という命令
プログラミングとは、機械に命令すること。
では、他にどんな「命令」があるのか
GoogleAppsScrip全体のリファレンスはこちら
https://developers.google.com/apps-script/reference/calendar/
Browserに対する命令
https://developers.google.com/apps-script/reference/base/browser
↑これらの「リファレンス」はよく参照することになります。
GASを書いてみよう
スクリプトエディタを開く
このスプレッドシートに紐づくスクリプトが開く
境野_GASレクチャー
コピペして実行してみよう。
function myFunction() {� var name = Browser.inputBox('Enter your name', Browser.Buttons.OK_CANCEL);� Logger.log(name + 'が入力されました');�}
実行するとinputBoxが
スプレッドシートの方に出る
コピペして実行してみよう。
名前を入力して「OK」を押す
スクリプトエディタに戻って
ログを表示する
入力された文字がログに出力されている
下記を試してみよう。
何が起こってるか
プログラムが実行されると、
ダイアログが表示される
入力された文字列を
プログラムが受け取る
入力された文字列 + ‘が出力されました’
という形にしてログに出力する
こういう意味です
function myFunction() {� var name = Browser.inputBox('Enter your name', Browser.Buttons.OK_CANCEL);
� Logger.log(name + 'が入力されました');�}
myFunction という名前の「関数=function」です。
こういう意味です
function myFunction() {� var name = Browser.inputBox('Enter your name', Browser.Buttons.OK_CANCEL);
� Logger.log(name + 'が入力されました');�}
1) この関数はここから始まって
3) ここまでです
2) 赤四角の中が関数の実体で
関数は複数書けます
function myFunctionA() {� Logger.log('ファンクションAです');�}
function myFunctionB() {� Logger.log('ファンクションBです');�}
この場合、myFunctionA と myFunctionB は別の関数です。
myFunctionAを実行しても、Bは実行されません。
さっきのコード解説 (今は「なんとなく」でいい)
function myFunction() {� var name = Browser.inputBox('Enter your name', Browser.Buttons.OK_CANCEL);
� Logger.log(name + 'が入力されました');�}
Browser(画面)に、[テキスト入力ダイアログ(ポップアップ)」を出してね。
メッセージは「Enter your name」にして、
OKボタンとCancelボタンを出してね。
→入力された文字列を受け取る
コード解説 (今はなんとなくでいい)
function myFunction() {� var name = 'Google太郎';
� Logger.log(name + 'が入力されました');�}
つまり、ここ全体が「入力された文字」になる
コード解説 (今はなんとなくでいい)
function myFunction() {� var name = 'Google太郎';
� Logger.log(name + 'が入力されました');�}
受けっとた文字列を、name という 変数 に 代入する
(name の中身が ‘Google太郎’ になる)
コード解説 (今はなんとなくでいい)
function myFunction() {� var name = 'Google太郎';
� Logger.log(name + 'が入力されました');�}
name の後ろに ‘が入力されました’ をくっつけて ログに出力する
コード解説 (今はなんとなくでいい)
function myFunction() {� var name = ‘Google太郎’;
� Logger.log(name + 'が入力されました');�}
‘Google太郎が入力されました’ が ログに出力される
もちょっと実用的なヤツを書いてみよう
スプレッドシートにあるアドレスにメールを送る君
下記のシートを作成してください
「シート1」にこれらを記入してください
スクリプトエディタを開く→下記をコピペする!
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);� }�}
実行する★実際にメールが送信されるので宛先には注意ね!
1. sendMailを選ぶ
3.成功すればメールが届く
2.実行する
(認証画面が出たら認証する)
何をやったか
コード全体はこれ(今はわからなくていいデス)
大雑把に言うとこうなる
スプレッドシートから情報の「かたまり」を取得する
かたまり=メアドと宛先と本文が入ってる
「かたまり」から1つずつ取り出す
メールを送信する
レクチャー終わったら理解できます
関数
変数
メソッドの呼び出しと戻り値
ループ
配列
引数ありのメソッド呼び出し
大事なこと:エラーは当たり前にでます
エラーはプログラムの間違いを教えてくれます。
うまく付き合っていきましょう!
...など、いっぱい出ます。いやマジで。
くじけないでね。
よくある原因
Typo(タイポ)
打ち間違い。’company’ が ‘conpany’になってたり。
カッコの閉じ忘れ
Logger.log(‘あいうえお’; とか。
文末の;を書き忘れる
「1つの命令はここまでです」というための目印が;です (GASでは)
大文字小文字のミス
Logger.Log(‘あいうえお’); はエラーになる。(正しくは Logger.log )
全角半角ミス
Logger.log(‘あいうえお’); はエラーになる。赤字部分が「全角」だから
Google Apps Scriptとは?
Googleのアプリたちと話ができるプログラム言語、ってこと。
「まったく新しい言語」ではなくJavascript がベース。
レクチャ内で「わからなかったら調べる」アクションが出てきますが、
検索ワードとして「javascript 配列」みたいなワードになるのはこのためです。
Javascript(の一部)をマスターしてもらいます!
事前準備:この記号、入力できます?
バックスラッシュ
Win :「¥」あるいは「ろ」�Mac:「option + ¥」
パイプ
shift+¥
すべて「半角」で!
全角だとエラーになります。
GASのキホン
GAS使いになるためにマスターしてほしいこと
変数
変数は箱。箱に値を入れられる。
function variable1() {� var num;� num = 10;� Logger.log(num);�}
1.スクリプトエディタに書く
2.保存する
3.実行する
4.ログを見る
sendMail() の下にコピペして variable1 を実行してください
ログの見方
■見方1
メニュー>表示>ログ
■見方2(ショートカット)
Win: Ctrl+Enter
Mac: Cmd+Enter
ログって何?
プログラムの実行時の情報をテキストで出力したもの。
変数の中身や、どこまでプログラムが来ているかを確認したりできる。
あるいはプログラムの動作を「ログファイル」に記録しておくことで、後から実行記録として動作確認の手がかりにしたりする。
変数は箱。箱に値を入れられる。
function variable1() {� var num; ①� num = 10; ②� Logger.log(num); ③�}
num
①numという名前の箱を用意する
num
②numに10を
「代入」する
10
③num(の中身)を
ログに出力する
変数は上書きできる
function variable1() {� var num;� num = 10;� Logger.log(num);�
num = 20;� Logger.log(num);�}
変数は複数書ける
function variable2() {� var kokugo;� var sansu;� var eigo;� var total;� � kokugo = 80;� sansu = 100;� eigo = 60;�� total = kokugo + sansu + eigo;� � Logger.log(total);�}
何をしているか
説明してみよう
変数で足し算できる
function variable2() {� var kokugo;� var sansu;� var eigo;� var total;� � kokugo = 80;� sansu = 100;� eigo = 60;�� total = kokugo + sansu + eigo;� � Logger.log(total);�}
変数で足し算(計算)できます
「コメント」は実行されない
function variable2() {
/*
変数の宣言と
変数への代入
*/� var kokugo;� var sansu;� var eigo;� var total;�� kokugo = 80;� sansu = 100;� eigo = 60;�
// 合計を計算して出力� total = kokugo + sansu + eigo;� Logger.log(total);�}
コメントの使いみち
やってることの説明などを書く。
上級者になると「プログラム自体をみればやってることはわかるので、コメントを書いておくと両方メンテナンスする必要があるので、そゆコメントは少ない方がいい」になる
複数行のコメント
/* から始まって
*/ で終わる中はコメントになる
1行コメント
// の後がコメントになる
算術演算子
どういうことができるの?の調べ方
[Javascript 算術演算子] で検索してみてください!
下記の5つについて調べてください。(すべて半角記号)
+ (プラス=たす)
- (マイナス=ひく)
* (アスタリスク=かける)
/ (スラッシュ=わる)
% (パーセント=あまり)
問題:3科目の平均を出力してください
function average3Test() {� var kokugo = 80;� var sansu = 100;� var eigo = 60;� var average;���
Logger.log(average);�}
変数の「宣言」と同時に「代入」もできる
ここに自由に書いてください
3教科の平均点が出力されたらOK
回答案: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のログの仕様なので気にしない!
回答案:averageを使わなくてもイケル
function average3Test() {� var kokugo = 80;� var sansu = 100;� var eigo = 60;�� Logger.log((kokugo + sansu + eigo) / 3);�}
averageという変数にいれず、
直接計算結果を出力も可能。
averageという変数に入れることで、その値が「何を意味しているのか」がわかりやすくなるので、私はaverageを用意したい派
文字列結合
文字列結合の実験
function stringTest() {� var firstName = '太郎';� var lastName = 'Google';� � // 文字列を結合する� Logger.log('こんにちは ' + lastName + firstName + ' さん');�� // 改行は \n で表現できる� Logger.log('今日はとても\nいい天気ですね!');�}
文字列は + で繋げられる
変数には文字列も入れられる
バックスラッシュ
Win :「¥」あるいは「ろ」�Mac:「option + ¥」
文字列のこと
コード: Logger.log(“最近は\”スプラトゥーン2\”がマイブームです。”);
出力: 最近は”スプラトゥーン2”がマイブームです。
Javascriptのルール
初めての人が困るところ(と私が思うところ)
どこが「決められた」部分で、
どこが「好きにしていい」部分なのかわからない。
例えば改行とか、スペースとか、大文字小文字は区別するのかとか。
この記号は必要なのかなくてもいいのか、とか。。。
2種類の「決まりごと」があります。
言語として決まっていること
プログラムは「半角英数記号」で書く
どこがおかしいでしょうか?
言語として決まっていること
プログラムは「半角英数記号」で書く
ここが「全角」になってる
決まっていること「javascript 予約語」(ググってみる)
function myFunction() {� var new = "あたらしい";� Logger.log(var new);�}
newは予約語なので
このまま実行すると
エラー
スクリプトエディタが予約語を教えてくれる
青色 = 変数宣言
紫色 = 予約語
水色 = 宣言済の変数
書く人のマナー(コーディングルール)
例えば...
見やすくするマナー
function myFunction(){var kokugo=80;var sansu=100;var eigo=60;var total;Logger.log((kokugo+sansu+eigo)/3);}
全部を1行で書いても動くけれど、わかりにくい!
イコールを縦に揃えることで
パッとみてわかる
インデントすることで
どこまでがmyFunctionの中
なのか視認しやすくなる
JSではインデントは
半角スペース2個がルール
ここに半角スペースがあることで視認性が上がる
ここに半角スペースがあることで視認性が上がる
ここに半角スペースがあることで視認性が上がる
今までのファイルを保存してこの章を完了します
名前を
「基本的なこと」
にしてください
条件分岐
新しいスクリプトファイルを作成
名前を
「条件分岐」
にしてください
プログラムはフローチャートで表現できる
http://www.edu-ctr.pref.okayama.jp/jyose/kyoiku_shien/jweb/b/b2i1kyouzai3.htm
「もし●●なら」がif文
http://www.edu-ctr.pref.okayama.jp/jyose/kyoiku_shien/jweb/b/b2i1kyouzai3.htm
朝起きる;
�登校の準備をする;
if (雨が降っている) {� 雨具を準備する;�}�
�家を出る;�
学校に到着;
「もし●●なら」がif文
http://www.edu-ctr.pref.okayama.jp/jyose/kyoiku_shien/jweb/b/b2i1kyouzai3.htm
朝起きる;
�登校の準備をする;
if (雨が降っている) {� 雨具を準備する;�}�
�家を出る;�
学校に到着;
雨が降っているときだけ
実行される処理
if文の「条件式」
if (条件式) {� 条件式がtrueの場合に実行する処理�}
「条件式」は 真偽値(true か false) になるもの
(例)
if ( num > 10 ) // numが10より大きければ()の中がtrueになる
if ( str === ‘おはよう’ ) // stgが文字列「おはよう」と一致すればtrue
この記号はあとでやります
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より小さい');� }
}�
出力先のセル
ここは自由に設定可能
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の時に
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 の時に
実行される処理
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以上');� }�}
条件式を増やせる
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が始まって
この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!');� }�}
出力される結果は同じです。
この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
なんちゃってボット
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() を増やしてみよう!
Tips ウィンドウを2つ並べるとやりやすいです
条件式と比較演算子・論理演算子
Javascript 比較演算子
「===」とか「>=」「<=」とか
(「同じかどうか」を比較するときは「==」じゃなくて「===」を使う!)
Javascript 論理演算子
「&&」と「||」と「!」
「かつ」と「または」と反転
// 論理演算子の例
if( (x>=50) && (x<100) ) {� Logger.log('xが50以上かつ100未満です');�}
ここまでのまとめテスト!
たかし君のテストの点数を評価する
たかし君は国語、算数、英語のテストを受けました。
国語は80点、算数が100点、英語は60点でした。
この学校では3教科の平均によって下記のように成績が決まっています
また、お母さんから「平均点が75点以上だったらお小遣いup」を約束されています。
たかし君の各教科の点数に応じて、
を出力するプログラムを書きなさい。ただし出力は下記のフォーマットとする
今回のたかし君の平均点は●点です。
よって成績は「●(優、良、可、不可のいずれか)」でした。
お小遣いアップ(「できました。」あるいは「できませんでした。」)
この続きを書いてください
function takashi() {� var kokugo = 80;� var sansu = 100;� var eigo = 60;� � /*� ここに処理を書く
出力はLogger.logで� */�}
■3教科の平均によって下記のように成績が決まっています
■「平均点が75点以上だったらお小遣いup」を約束されています。
成績に応じて、
を出力する。出力は下記のフォーマットとする
----------------------------------------------------------------------
今回のたかし君の平均点は●点です。
よって成績は「●(優、良、可、不可のいずれか)」でした。
お小遣いアップ(「できました。」あるいは「できませんでした。」)
ここの値を色々変えても正しい計算結果になるようにね!
この続きを書いてください (回答案はコメント欄に)
function takashi() {� var kokugo = 80;� var sansu = 100;� var eigo = 60;�
// 必要なモノはこれ
var average; //平均
var grade; //成績
//averageを計算する
//gradeを計算する
//出力する�}
■3教科の平均によって下記のように成績が決まっています
■「平均点が75点以上だったらお小遣いup」を約束されています。
成績に応じて、
を出力する。出力は下記のフォーマットとする
----------------------------------------------------------------------
今回のたかし君の平均点は●点です。
よって成績は「●(優、良、可、不可のいずれか)」でした。
お小遣いアップ(「できました。」あるいは「できませんでした。」)
ここの値を色々変えても正しい計算結果になるようにね!
ショートカットあります
関数の実行
ログの表示
配列
新しいスクリプトファイルを作成
名前を
「配列とループ」
にしてください
配列ってなんぞ?
変数は1つの値を格納できる。
var num = 10;
var numbers = [10, 30, 5, 25];
配列は複数の値を格納できる。
num
10
0
1
2
3
10
30
5
25
numbers
用語をおぼえとこう
var numbers = [10, 30, 5, 25];
0
1
2
3
10
30
5
25
numbers
配列名
(自由に決めていい)
要素
(各インデックスの中身)
インデックス
(0から始まる)
書いてみる (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); // これで「配列」を出力できる�}
書いてみる
function myArray() {� var fruits = ['banana', 'orange', 'apple'];� � // 要素を取り出す� Logger.log(fruits[2]);�� // 要素を上書きする� fruits[2] = 'melon';� Logger.log(fruits[2]);� � // 要素を追加する� fruits[3] = 'peach';� Logger.log(fruits); // これで「配列」を出力できる�}�
このやり方だと
一番大きいインデックスを知らないと、その次に追加できない。
配列を扱うための「道具」が用意されている
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')); // 存在しない場合、何が表示されるか?� }
どんな「道具」があるか調べるには?
「Javascript 配列」とか「Javascript array」で検索!!
(「console.log」が出てきたら「Logger.log」に置き換えること)
いっぱいある。
覚えられない。
覚えなくていい。
何かしようとした時に自分で調べて試せることが大事。
↓
例「Javascript 配列 追加」とかでググれば出てくる!
おみくじサンプル (コピペして実行)
function omikuji() {� var omikuji = ['大吉','中吉', '吉', '凶'];
� // omikuji[x] で要素を取り出せる。xを0から3のランダムな整数にしたい。�� var x = Math.floor(Math.random() * 4); //0~3のランダム整数� Logger.log( omikuji[x] );�}
配列の中身の数を変えて試してみよう。
「最大インデックス = 赤字部分の数字」にしよう
おみくじサンプル (コピペして実行)
function omikuji() {� var omikuji = ['大吉','中吉', '吉', '凶'];
� // omikuji[x] で要素を取り出せる。xを0から3のランダムな整数にしたい。�� var x = Math.floor(Math.random() * omikuji.length);� Logger.log( omikuji[x] );�}
4ってつまり配列の要素数のこと
ループ
ループ
「処理の繰り返し」のための構文。
例:1以上10以下の整数を出力するプログラム
ループ
「処理の繰り返し」のための構文。forとwhileがあります。
例:1以上10以下の整数を出力するプログラム
<疑問>
これのどこが「繰り返し」なの?
<回答>
数字は毎回変わるけど、
「数字を出力する」という処理は繰り返してる
for文で書いてみる
function loopFor() {� for (var i = 1; i <= 10; i++ ) {� Logger.log(i);� }
}
「配列とループ.gs」 の下の方に書いて実行してみよう!
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を足す)
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を出力するというのは
つまりこういうこと
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つずつ増えてる
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を入れて出力
をしたい
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を代入して「処理」する
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を足す
for文の解説 (詳しく)
function loopFor() {�
for (var i=1; i<=10; i++){
Logger.log(i);
}
�}
こう書くとそれが実現できる
iを1から始めて 何か処理する。
iが10になるまで 繰り返す。
処理が終わるたびに iに1を足す。
1から10までの「合計」を出力する
function oneTen() {� var total = 0;� � for (var i=1; i<=10; i++) {� total = total + i;� }� � Logger.log('合計は' + total + 'です');�}
ポイントがあります
function oneTen() {� var total = 0;� � for (var i=1; i<=10; i++) {� total = total + i;� }� � Logger.log('合計は' + total + 'です');�}
ポイント1
1つの変数の中身を「更新」していく
ポイント2
自分自身に、「自分自身にiを加えたもの」を代入する
ポイントがあります
function oneTen() {� var total = 0;� � for (var i=1; i<=10; i++) {� total = total + i;� }� � Logger.log('合計は' + total + 'です');�}
この式の意味は
右辺の計算結果を、左辺に代入する
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になる
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になる
今度は while で書いてみる
function loopWhile() {� var i = 1;� while (i <= 10) {� Logger.log(i);� i++;� }�}
whileのルール
function loopWhile() {� var i = 1;� while (i <= 10) {� Logger.log(i);� i++;� }�}
whileの後の ( ) 内がtrueだったら
{ } 内が実行される
whileのルール
function loopWhile() {� var i = 1;� while (i <= 10) {� Logger.log(i);� i++;� }�}
今回の条件は「iが10以下ならば」
1回のループが終わるごとに iに1を足す
↓
2回目のループのときには 「i <= 10」のiは2になってる。
whileのルール
function loopWhile() {� var i = 1;� while (i <= 10) {� Logger.log(i);� � }�}
もし「i++;」が無いと、
「i <= 10」は常にtrueになる (iは常に1なので)ので
「無限ループ」になる!(処理が終わらない)
ループの「中断」
1から100までの整数一つずつ順番に7をかけた数を出力するプログラム
→ 100以上の結果は出力しない(プログラムを終了する)ようにしたい
function loopBreak() {�� for ( var i = 1; i <= 100; i++ ) {� Logger.log('結果:' + (i * 7) ); � }
� Logger.log('終了しました'); �}
ループの「中断」: 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 を通るとループを抜ける
これはループの外なので
ループを抜けた後に実行される
ループの「スキップ」
function loopContinue() {� var result;
� for ( var i = 1; i <= 100; i++ ) {� result = i * 7;� Logger.log('結果:' + result); � }
� Logger.log('終了しました'); �}
(再掲)1から100までの整数一つずつ順番に7をかけた数を出力するプログラム
→ 結果が奇数の時だけ出力したい(偶数は出力しない)
ループの「スキップ」: 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を通ったときはこれは実行されない
ループの課題
ループ課題
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);�}
ループをいつ使うか
配列の中身の処理
var fruits = ['banana', 'orange', 'apple'];�
この配列の中身を1つずつ取り出して処理したい。
例えば下記のような出力をしたい。
bananaが好きです
orangeが好きです
appleが好きです
こういう書き方もできるけど、、、
function forArray() {� var fruits = ['banana', 'orange', 'apple'];� � Logger.log(fruits[0] + 'が好きです');� Logger.log(fruits[1] + 'が好きです');� Logger.log(fruits[2] + 'が好きです');�}
要素を指定して取り出す
こういう書き方もできるけど、、、
function forArray() {� var fruits = ['banana', 'orange', 'apple'];� � Logger.log(fruits[0] + 'が好きです');� Logger.log(fruits[1] + 'が好きです');� Logger.log(fruits[2] + 'が好きです');�}
要素数が増えたら大変!!
for文で配列から要素を取り出す
function forArray() {� var fruits = ['banana', 'orange', 'apple'];� � for ( var i = 0; i < fruits.length; i++ ) {� Logger.log(fruits[i] + 'が好きです');� }�}
fruits.length = fruits配列の長さ
i がインデックスを示す
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増やす
for文で配列から要素を取り出す
function forArray() {� var fruits = ['banana', 'orange', 'apple', 'grape'];� � for ( var i = 0; i < fruits.length; i++ ) {� Logger.log(fruits[i] + 'が好きです');� }�}
配列の要素数が増えても、出力ロジックを変える必要がなくなる。
配列からの取り出し方 その2
forEachを使う
function forEachTest() {� var fruits = ['banana', 'orange', 'apple'];� � fruits.forEach(function(fruit){� Logger.log(f + 'がおいしい');� });�}
forEach解説
function forEachTest() {� var fruits = ['banana', 'orange', 'apple'];� � fruits.forEach(function(fruit){� Logger.log(fruit + 'がおいしい');� });�}
要素1つずつに対して
functionの処理をしてね
配列から取り出した1つの要素は
fruitっていう変数に入れてね
変数名は自由に決められる
fruitsから1つ取り出すからfruitにした
functionの処理
この配列の
少なくとも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 + 'がおいしい');� });�}
どちらも
結果は同じ
なぜ配列が大事なのか?
スプレッドシートの情報は「配列」として扱う
この1行を
[‘たかし’, ‘国語’, ’80’]
という配列として扱う
スプレッドシートの情報は「配列」として扱う
これ全部を
[
[‘たかし’, ‘国語’, ‘80’],
[‘たかし’, ‘算数’, ‘100’],
[‘たかし’, ‘英語’, ‘60’],
[‘みゆき’, ‘国語’, ‘70’],
[‘みゆき’, ‘算数’, ‘50’],
[‘みゆき’, ‘英語’, ‘100’],
]
という二次元配列で扱う
二次元配列くわしく(1)
配列の復習。1つの「配列」に複数の「要素」がある
// 書き方
var numbers = [10, 30, 5, 25];
0
1
2
3
10
30
5
25
numbers
配列名
要素の1つに 5 という
数字を格納している
インデックス
二次元配列くわしく(2)
要素には「数字」だけじゃなく「文字列」も入れられる
[‘たかし’, ‘国語’, 80]
0
1
2
‘たかし’
‘国語’
80
二次元配列くわしく(3)
要素には「数字」だけじゃなく「配列」も入れられる。
(配列の要素の中に配列が入ってる)
0
1
2
0
1
2
‘たかし’
‘国語’
80
0
1
2
‘たかし’
‘算数’
100
0
1
2
‘たかし’
‘英語
60
(イメージ図)
でっかい配列の各要素に、
ちっちゃい配列が入ってる
二次元配列くわしく(4)
「行」の情報が1つの要素になっている配列ができあがる
0
1
2
0
1
2
‘たかし’
‘国語’
80
0
1
2
‘たかし’
‘算数’
100
0
1
2
‘たかし’
‘英語
60
「1行目」の情報
「2行目」の情報
「3行目」の情報
やってみよう
シートを追加して
シート名を「配列」にする。
↓これをA1から貼り付ける
たかし | 国語 | 80 |
たかし | 算数 | 100 |
たかし | 英語 | 60 |
みゆき | 国語 | 70 |
みゆき | 算数 | 50 |
みゆき | 英語 | 100 |
やってみよう
function seiseki() {� var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('配列');� var seiseki = sheet.getDataRange().getValues();�� Logger.log(seiseki);�}
これがseisekiの中身
二次元配列になってる
今は意味がわからなくてOK。丸写ししてください。
意味は「そのシートにあるデータを全部取ってきて
seisekiという名前の配列に入れる」
ログを整形してみる
[
[たかし, 国語, 80.0],
[たかし, 算数, 100.0],
[たかし, 英語, 60.0],
[みゆき, 国語, 70.0],
[みゆき, 算数, 50.0],
[みゆき, 英語, 100.0]
]
整形
この値を取りたいときにどうするか
[
[たかし, 国語, 80.0],
[たかし, 算数, 100.0],
[たかし, 英語, 60.0],
[みゆき, 国語, 70.0],
[みゆき, 算数, 50.0],
[みゆき, 英語, 100.0]
]
ログを整形してみる
[
[たかし, 国語, 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]
イメージ図
0
1
2
0
1
2
‘たかし’
‘国語’
80
0
1
2
‘たかし’
‘算数’
100
0
1
2
‘たかし’
‘英語
60
「1行目」の情報
「2行目」の情報
「3行目」の情報
seiseki[1][2]
書いてみよう
function seiseki() {� var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();� var seiseki = sheet.getDataRange().getValues();�� Logger.log(seiseki[1][2]);�}�
これでたかしの算数の点数が取り出せる
問題:みゆきの算数の点数を取り出したい
function seiseki() {� var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();� var seiseki = sheet.getDataRange().getValues();�� Logger.log(seiseki[x][x]);�}�
みゆきの算数の点数を
出力するにはどうしたらいいか?
覚え方:[縦][横] の順で 「0起算」でカウント
ま
ず
縦
から
次に横を指定
0
1
2
3
4
5
0
1
2
[4][2]
二次元配列についての補足説明
ここ、つまづきポイントだなと思ったので、説明記事を書いてみました。
GASでスプレッドシートを扱うときの二次元配列の教え方
https://qiita.com/sakaimo/items/d535079b5bee4eed8eb1
配列+ループの課題
配列課題(必須)
たかし君の点数の平均を出力するプログラムを、for文を使って書いてください
function scoreAverage() {� var takashiScore = [80, 100, 60];��
� � Logger.log(xxxxxxx);�}
↓出力結果はこれ
//ここにコードを書いてね
//要素を一つずつ取り出して足す(合計)
//合計から平均を出す
配列課題(ヒント)
function forArray() {� var fruits = ['banana', 'orange', 'apple'];� � for ( var i = 0; i < fruits.length; i++ ) {� Logger.log(fruits[i] + 'が好きです');� }�}
以前出てきた下記のコードがヒントです。
「配列の要素を、ひとつずつ取り出して、取り出した要素に対して処理をする」
課題の解説
配列課題(解説:わたしはこう考えた)
function scoreAverage() {� var takashiScore = [80, 100, 60];�� // 出したい結果は何か?� var total = 0;� var average = 0;� � // ここに「処理」を書いて、totalとaverageを作る。�� � Logger.log(xxxxxxx);�}
totalとaverageを作るのがゴール
(初期値としてゼロを入れとく)
そのための「処理」を考える
配列課題(解説:わたしはこう考えた)
function scoreAverage() {� var takashiScore = [80, 100, 60];�� // 出したい結果は何か?� var total = 0;� var average = 0;� � // まずtotalを作る。�� � Logger.log(xxxxxxx);�}
まず totalを考える。
「配列の中身を全部足したい」
↓
「配列を一つ取り出してtotalに足す」
「その次の要素を取り出してtotalに足す」
...を繰り返すことでできそう。
配列課題(解説:わたしはこう考えた)
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);�}
配列課題(解説:わたしはこう考えた)
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);�}
配列課題(任意)
でんぱ組.inc 問題
function dempaTest() {� // 2011年12月25日までのメンバー(加入順)� var dempagumi = ['古川未鈴', '相沢梨紗', '夢眠ねむ', '成瀬瑛美', '跡部みぅ'];� � // 2011年12月25日に[跡部みぅ]が脱退。[藤咲彩音]と[最上もが]が加入� dempagumi.xxx(...);� dempagumi.xxx(...);�� // 2017年8月6日に[最上もが]が脱退� � // 2017年12月30日に[鹿目凛]と[根本凪]が加入� � // この時点でのメンバーを加入順に1人ずつ出力してください
// (ループをつかうこと)��}
考えてもわからない!
[javascript 配列 追加]
とか
[javascript 配列 削除]
で検索だ!
↓出力結果はこれ
二重ループの課題
「かけ算九九」を出力するプログラム。
出力は右記のようにしてください。
function kuku() {�
�}
9✕9まで
二重ループの課題
ループ1
1から9まで増えていく
二重ループの課題
ループ1
1から9まで増えていく
ループ2
1から9まで増えていく
ループ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のループ
ループ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
こうなる
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)
オブジェクト
新しいスクリプトファイルを作成
名前を
「オブジェクト」
にしてください
オブジェクト
これまでは「変数」と「配列」として値を扱ってきました。
もう一つの形が「オブジェクト」
正確に言うと、「配列は、オブジェクトの一部」だそうです。
配列とオブジェクト
配列はインデックスをキーにして値を扱える
オブジェクトはプロパティをキーにする
seiseki[0] // ‘たかし’のこと
seiseki[2] // 80のこと
seiseki =
seiseki =
seiseki.name // ‘たかし’のこと
seiseki.score // 80 のこと
0
1
2
‘たかし’
‘国語’
80
name
subject
score
‘たかし’
‘国語’
80
箱に名前を付けられる
箱の名前で呼び出せる
インデックスで呼び出せる
オブジェクトのコード
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 があり、
それぞれのプロパティに値がある
オブジェクトのコード
var person = { id: 100, name: 'さかいも', food: 'フライドポテト' };
// ↑これは↓こう書いても同じ (改行しただけ)
var person = {� id: 100,� name: 'さかいも',� food: 'フライドポテト'�};
オブジェクトのコード
var person = { id: 100, name: 'さかいも', food: 'フライドポテト' };
// ↑これは↓こう書いても同じ (改行しただけ)
var person = {� id: 100,� name: 'さかいも',� food: 'フライドポテト'�};
id: 100
name: ‘さかいも’
food: ‘フライドポテト’
「personオブジェクト」
配列との違い
function arrayAndObject() {� var array = ['あ','い','う'];� var object = { id:100, name:'さかいも', food:'フライドポテト'};� � Logger.log(array);� Logger.log(object);�}
配列は順番どおり並んでる
オブジェクトは並び順は保証されていない。
(上ではidが最初だけどログはnameが最初)
オブジェクトの実験
「オブジェクト」のシートを追加
左記の表を作ってください。
データは1行でいいです!
コピペで実行だ!
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);�}�
今回はログではなく、
スプレッドシートに
「出力」されます
コード解説
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);�}�
シート名が「オブジェクト」になってるシートを取得する
コード解説
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
コード解説
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);�}
出力したい文字列を作る
コード解説
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);�}
セルに出力する
オブジェクトの使いみち
例えば、テストの成績データを扱うとする。
seiseki = [たかし, 国語, 80];
seiseki = {
name: "たかし",
subject: "国語",
score: 80
};
配列で表現するとこうだけど
オブジェクトだとこう
オブジェクトの使いみち
例えば、テストの成績データを扱うとする。
seiseki = [たかし, 国語, 80];
seiseki = {
name: "たかし",
subject: "国語",
score: 80
};
配列だと
インデックスの[2]に点数が入ってる、を覚えておかないとならない。
seiseki[2]
オブジェクトだと
seiseki.score で点数が取得できる
データ型
Javascriptで扱えるデータ型
データ型 | 説明 | サンプル |
String | 文字列。 | var str = ‘あいうえお’; |
Number | 数値。整数も小数も。 | var num = 100; |
Boolean | 真偽値。true か false | true または false |
undefined | 値が未定義なことを表す | |
null | 特殊なキーワード(後述) | |
Object | オブジェクト | var person = {� name: ‘Bob’,� sex: ‘male’,� age: 25� } |
「文字列」と「数字」は違う
function dataType() {� � var s = '3'; // Stringとしての3� var n = 5; // Numberとしての5� � // これらを足し算するとどうなるか?� Logger.log(s + n);�}
「文字列」と「数字」は違う
function dataType() {� � var s = '3'; // Stringとしての3� var n = 5; // Numberとしての5� � // これらを足し算するとどうなるか?� Logger.log(s + n);�}
文字列がある場合は
「文字列連結」になっちゃう。
文字列を数字に変換する関数
function dataType() {� � var s = '3';
var n = 5;� � // 文字列を数字に変換する parseInt()� Logger.log( parseInt(s, 10) + n );�}�
[javascript parseInt] で検索!!!
stringを、
10進法の数字にparseしろ
という命令
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になるもの] で検索!
特別な値 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'を返す、という関数
特別な値 undefined, null
function undefTest() {� var test;� Logger.log(test);�}
function nullTest() {� var str = 'abc';� var m = str.match(/xyz/);� Logger.log(m);�}
「未定義であること(undefined)」
「該当する値がないこと(null)」
ここ が詳しく説明してる
関数
新しいスクリプトファイルを作成
名前を
「関数」
にしてください
「関数を呼び出す」ということ
function sono1() {� Logger.log('1.ここが実行されて');� sono2();� Logger.log('3.ここに戻ってくる');�}��function sono2() {� Logger.log('2.ここに来て');�}
sono1を実行してください
こういう順番で処理されます
コピペして「sayTest」を実行してログを見る
function sayTest() {� sayGoodBye();�}��function sayGoodBye() {� sayHello();� Logger.log('Good Bye!');�}��function sayHello() {� Logger.log('Hello!');�}
関数を呼ぶ、ということ(1)
function sayHello() {� Logger.log('Hello!');�}
function sayGoodBye() {� sayHello();� Logger.log('Good Bye!');�}
function sayTest() {
sayGoodBye();
}
1.Hello!が出力される
(続く)
関数を呼ぶ、ということ(2)
function sayHello() {� Logger.log('Hello!');�}
function sayGoodBye() {� sayHello();� Logger.log('Good Bye!');�}
function sayTest() {
sayGoodBye();
}
2.処理が終わったら
「呼び出し元」に戻る
(sayHello() の次の処理に移る)
3.Good Bye! が出力される
4.sayGoodByeの次の行に移る
(何も無いので終了)
実行順序の確認
function sayTest() { (1)� sayGoodBye(); (2)�}�(8) 終了
�function sayGoodBye() { (3)� sayHello(); (4)� Logger.log('Good Bye!'); (7)�}��function sayHello() { (5)� Logger.log('Hello!'); (6)�}
関数:「引数」と「戻り値」(speechを実行してみよう)
// 引数と戻り値の例�function speech() {� var name = 'sakaimo';� var speech = createSpeechText(name);� � Logger.log(speech);�}��function createSpeechText(name) {� var text = 'はじめまして、' + name + 'と申します';� return text;�}
関数:「引数」と「戻り値」
// 引数と戻り値の例�function speech() {� var name = 'sakaimo';� var speech = createSpeechText(name);� � Logger.log(speech);�}��function createSpeechText(name) {� var text = 'はじめまして、' + name + 'と申します';� return text;�}
関数に渡す値 (=実引数)
関数が呼び出し元に返す値(=戻り値)
関数定義に書く引数 (=仮引数)
デバッグしてみよう
1.var name にブレイクポイントを付けて
2.speech関数を「デバッグ」する
3.「ステップイン」を押して1行ずつ進める
4.この時点で変数nameに何が入っているかを確認することができる!!
関数の例:三角形の面積を求めるプログラム
「底辺」と「高さ」から「三角形の面積」を計算する君をつくる。
求めたい三角形の面積が2つあるとする。
イメージ図
底辺 10
高さ 20
答え
100
底辺 30
高さ 40
答え
600
底辺 ✕ 高さ ÷ 2
底辺 ✕ 高さ ÷ 2
イメージ図+ベタに書くとこうなる
底辺 10
高さ 20
答え
100
底辺 30
高さ 40
答え
600
底辺 ✕ 高さ ÷ 2
底辺 ✕ 高さ ÷ 2
イメージ図+ベタに書くとこうなる
底辺 10
高さ 20
答え
100
底辺 30
高さ 40
答え
600
底辺 ✕ 高さ ÷ 2
底辺 ✕ 高さ ÷ 2
底辺 ✕ 高さ ÷ 2
底辺 ✕ 高さ ÷ 2
三角形の面積を計算する
という処理は同じ
共通の処理を切り出しておく
→「関数」を作る
面積計算してくれる君
インプット
高さ
底辺
処理
底辺 ✕ 高さ ÷ 2
アウトプット
面積
(2)インプットを受け取る
(3)計算する
(4)結果を返す
(1)関数の名前
共通の処理を切り出しておく
→「関数」を作る
底辺 10
高さ 20
答え
100
底辺 30
高さ 40
答え
600
底辺と高さを渡すと
三角形の面積を返してくれる
同
同
面積計算してくれる君
インプット
高さ
底辺
処理
底辺 ✕ 高さ ÷ 2
アウトプット
面積
コードにするとこうなる(書いてみよう)
function calcTriangleArea(base, height) {� var area = base * height / 2;� return area;�}
コード解説
function calcTriangleArea(base, height) {� var area = base * height / 2;� return area;�}
(1)関数の名前
(2)インプットを受け取る
(3)計算する
(4)結果を返す
関数を使うには「呼び出す」
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
になる
コード解説
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に代入する
コード解説
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 に結果が代入される
before
after
底辺 10
高さ 20
答え
100
底辺 30
高さ 40
答え
600
底辺 10
高さ 20
答え
100
底辺 30
高さ 40
答え
600
底辺 ✕ 高さ ÷ 2
底辺 ✕ 高さ ÷ 2
底辺 ✕ 高さ ÷ 2
面積計算してくれる君
関数のメリット1:使いまわせる
底辺 10
高さ 20
答え
100
底辺 30
高さ 40
答え
600
底辺 10
高さ 20
答え
100
底辺 30
高さ 40
答え
600
底辺 ✕ 高さ ÷ 2
底辺 ✕ 高さ ÷ 2
底辺 ✕ 高さ ÷ 2
面積計算してくれる君
3つ目の三角形が必要になっても、
底辺と高さを渡せばいいだけ
関数のメリット1:使いまわせる
底辺 10
高さ 20
答え
100
底辺 30
高さ 40
答え
600
底辺 10
高さ 20
答え
100
底辺 30
高さ 40
答え
600
底辺 ✕ 高さ ÷ 2
底辺 ✕ 高さ ÷ 2
底辺 ✕ 高さ ÷ 2
面積計算してくれる君
<使う側>
使いたい関数を呼ぶ
必要なら引数を渡す
だけで、結果がもらえる。
関数の中がどうなってるのかは
知らなくていい
<関数>
引数を受け取って
計算して
結果をreturnする
呼び出す(引数)
結果を返す
関数のメリット2:修正が一箇所で済む
底辺 10
高さ 20
答え
66.666
底辺 30
高さ 40
答え
400
底辺 10
高さ 20
答え
100
底辺 30
高さ 40
答え
600
底辺 ✕ 高さ ÷ 3
底辺 ✕ 高さ ÷ 3
底辺 ✕ 高さ ÷ 2
面積計算してくれる君
(そんなことないけど)
三角形の面積の公式が変わった場合
すべての計算箇所を修正する
ここも修正する必要あり
関数のメリット2:修正が一箇所で済む
底辺 10
高さ 20
答え
100
底辺 30
高さ 40
答え
600
底辺 10
高さ 20
答え
66.6
底辺 30
高さ 40
答え
400
底辺 ✕ 高さ ÷ 3
底辺 ✕ 高さ ÷ 3
底辺 ✕ 高さ ÷ 3
面積計算してくれる君
まとまっていれば
一箇所の修正でいい
引数は配列やオブジェクトでもいい
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;
}�}
ちょっと補足
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;
}�}
ここ値を「仮引数」という.
自由でいいに決めていい.
ちょっと補足
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」であっても
関数で課題
(ここまでの総復習的な)
たかし君のテスト再び (問題文は全く同じ)
たかし君は国語、算数、英語のテストを受けました。
国語は80点、算数が100点、英語は60点でした。
この学校では3教科の平均によって下記のように成績が決まっています
また、お母さんから「平均点が75点以上だったらお小遣いup」を約束されています。
たかし君の各教科の成績に応じて、
を出力するプログラムを書きなさい。ただし出力は下記のフォーマットとする
今回のたかし君の平均点は●点です。
よって成績は「●(優、良、可、不可のいずれか)」でした。
お小遣いアップ(「できました。」あるいは「できませんでした。」)
お題:30分
たかし君のテストの成績は「配列」になっています。
var score = [100, 80, 90];
<課題その1>
3教科の点数が入った配列を引数として渡すと、成績を判定して優,良,可,不可 のいずれかの文字列を返す関数 checkSeiseki を作りなさい。
<課題その2>
平均点を引数として渡すと、お小遣いup可能かどうかを返す関数 canMoneyUp を作りなさい。up可能な場合true, 不可能な場合falseを返します。
実行するのは takashiTest()
function takashiTest() {� var score = [100, 80, 90];
}
function checkSeiseki(xxx) {�
}
function canMoneyUp(xxx) {�
}
「やること」を日本語で書いてみる
その1をどう書くか
function takashiTest() {� var score = [100, 80, 90];
//その1:成績の配列を渡すと判定結果をくれる
var hantei = checkSeiseki(score);
}
<その1>
3教科の点数が入った配列を引数として渡すと、成績を判定して優,良,可,不可 のいずれかの文字列を返す関数 checkSeiseki を作りなさい。
checkSeisekiでは何をするか
function takashiTest() {� var score = [100, 80, 90];
//その1:成績の配列を渡すと判定結果をくれる
var hantei = checkSeiseki(score);
}
function checkSeiseki(score) {� // scoreの中身の平均を出す
// 平均点に応じて優良可不可を判定 (既出)
// 結果(優,良,可,不可)を return する
}
仕様
3教科の点数が入った配列を引数として渡すと、成績を判定して優,良,可,不可 のいずれかの文字列を返す
return の結果が hantei に入る
function takashiTest() {� var score = [100, 80, 90];
//その1:成績の配列を渡すと判定結果をくれる
var hantei = checkSeiseki(score);
}
function checkSeiseki(score) {� // scoreの中身の平均を出す
// 平均点に応じて優良可不可を判定 (既出)
// 結果(優,良,可,不可)を return する
}
「優,良,可,不可]のいずれかが
hanteiに代入される
その2は何をするのか
function takashiTest() {� var score = [100, 80, 90];
//その1:成績の配列を渡すと判定結果をくれる
var hantei = checkSeiseki(score);
// その2:平均点を渡すと小遣いupの可否をくれる
// 2-1.まず平均点を出す
var average = ...
}
function checkSeiseki(score) {� // scoreの中身の平均を出す
// 平均点に応じて優良可不可を判定 (既出)
// 結果(優,良,可,不可)を return する
}
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可能かどうかを返す
結果を出力する (回答例はコメント欄に)
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する
}
プログラムの改善ポイントがあるよね?
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回やってる!
→これをどうにかしてください。
任意課題:配列を受け取って平均を返す関数を追加しなさい
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する
}
スコープ
新しいスクリプトファイルを作成
名前を
「スコープ」
にしてください
スコープとは
変数の有効範囲、のこと。
宣言した変数が、どこから参照できるか/できないか
が決まっています。
関数の外に書く
var msg = 'Good Morning.';�Logger.log(msg);��function scopeTest() {� Logger.log('Hello.');�}��Logger.log('Good Bye.');
実行するのはこの関数
関数の外にあるコード
関数の外にあるコード
実行順序がこうなった
var msg = 'Good Morning.';�Logger.log(msg); (1)��function scopeTest() {� Logger.log('Hello.'); (3)�}��Logger.log('Good Bye.'); (2)
グローバル領域が先に実行されるというルール。
var msg = 'Good Morning.';�Logger.log(msg);��function scopeTest() {� Logger.log('Hello.');�}��Logger.log('Good Bye.');
関数
関数の外
=グローバル領域
呼び出した関数よりも先に、グローバル領域が上から順番に実行される。
※ 理由がない限りはグローバル領域には書かないほうがいい!
グローバルスコープとローカルスコープ
var globalMsg = 'Globalです';��function scopeTest1() {� var localMsg = 'Localです';�}��function scopeTest2() {� Logger.log(globalMsg);� Logger.log(localMsg);�}
さっき書いたスクリプトを削除してから下記を書く
実行するのはこの関数
エラーになる
scopeTest1の中で宣言された localMsgは、
その関数の外からは参照できない。
別スコープにある同じ名前の変数
var msg = 'Globalです';��function scopeTest1() {� var localMsg = 'Local その1です';�}��function scopeTest2() {� var localMsg = 'Local その2です';� Logger.log(localMsg);�}
これはOK
scopeTest1とは別の
の変数になる
問題:下記では何が出力されますか?
var msg = 'Globalです';��function scopeTest3() {� var msg = 'Localです';� Logger.log(msg); //ココでは何が出力されますか?�}
答え: Localです
var msg = 'Globalです';��function scopeTest3() {� var msg = 'Localです';� Logger.log(msg);�}
自分に近い方が優先される
ここまでで「キホン」終わり
...長かったよね。
ここまでで土台ができました。
[土台]
GAS(プログラム言語)のキホン
次は各アプリケーション特有の「使い方」をやります
[土台]
GAS(プログラム言語)のキホン
どゆこと? 例)スプレッドシートの場合
[土台]
GAS(プログラム言語)のキホン
シートから値を取ってくる
シートに値を入力する
シートをコピーする
...など「スプレッドシート」を操作する
↓GASだけどスプレッドシートは使ってない例
function sayTest() {� sayGoodBye();�}��function sayGoodBye() {� sayHello();� Logger.log('Good Bye!');�}��function sayHello() {� Logger.log('Hello!');�}
スプレッドシートに紐づく「スクリプトエディタ」にコードを書いていますが、
コードからスプレッドシートにアクセスはしていない。
という意味です。
↓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以上');� }�}
スプレッドシートに対して「操作」している
「操作する」って言っても難しくない
すでに学んだ「関数」が用意されています。
それを「使う」だけです。
自分で書いたGAS
シートのデータちょうだい
はいどうぞ
(例)
sheet.getRange("A5").getValue()
シートのA5にある値をちょうだい、という関数
つまりはこれと同じこと
底辺 10
高さ 20
答え
100
底辺 30
高さ 40
答え
600
底辺 ✕ 高さ ÷ 2
面積計算してくれる君
スプレッドシート
(これ以降、「SS」はスプレッドシートのことね)
新しいスクリプトファイルを作成
名前を
「スプレッドシート」
にしてください
SSの構造
1)スプレッドシートアプリケーション
(Officeでいうところの「エクセル」)
2)スプレッドシート
(ブックのこと)
3)シート
(シートのこと)
4)レンジ (セルの範囲)
SSでやりたいことってだいたいこの3つ
サンプル
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に何か書いてください
サンプル(解説)
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する
サンプル(解説)
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する
この処理は定番処理なので丸覚えしてください
処理をしたい「シート」を特定するコードです
ポイント
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する。
(余談) まとめて書ける
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
値の取得(複数のセル)
前ページのやり方だと、”A1”のセルしか取得できない。
実務では「範囲指定をせずに」
をやります。以前やった「二次元配列」の再登場。
↓
これから出てくるサンプルプログラムでやってみましょう。
リファレンスの見方
ココ↓に遷移します
https://developers.google.com/apps-script/reference/calendar/
[GoogleAppsScript リファレンス」で検索
スプレッドシートのリファレンス
うわ!英語かよ!わかんねぇよ!と思ったあなた
「GAS スプレッドシート 使い方」で検索だ。
いっぱいHITするのでそれを見てもいいと思う。
ただ、間違ってたり情報が古かったりするので、
「公式」な情報は
https://developers.google.com/apps-script/reference/
にある、というのは知っておいてください。
スプレッドシート実践 その1
(シートのデータを全部取ってきて処理する)
アンケートの集計GAS
やりたいこと
アンケート結果は
- 中華 3人
- 和食 2人
- 洋食 5人
でした。
メール送信
アンケートの集計GAS
やりたいこと
アンケート結果は
- 中華 3人
- 和食 2人
- 洋食 5人
でした。
メール送信
集計だけなら関数でできるね!
=countif(B2:B11,"中華")
今回はあえてGASでやるよ。
まずは日本語で考える
大きな「処理」の塊で考えると
「集計」して「メールする」
あたりまえに聞こえるけど、
ちゃんと「わけて」考えておく。
名前 | 食べたいもの |
沼田悠花 | 中華 |
室井千代乃 | 和食 |
中澤和歌子 | 洋食 |
石本春夫 | 洋食 |
菅谷優子 | 洋食 |
米山英明 | 洋食 |
大和田敏嗣 | 和食 |
倉持英司 | 中華 |
伴敏嗣 | 洋食 |
織田雄太 | 中華 |
コピペ用。皆さんA1からコピペしてください
すこし細かく日本語で考える
集計の部分
メール送信部分
名前 | 食べたいもの |
沼田悠花 | 中華 |
室井千代乃 | 和食 |
中澤和歌子 | 洋食 |
石本春夫 | 洋食 |
菅谷優子 | 洋食 |
米山英明 | 洋食 |
大和田敏嗣 | 和食 |
倉持英司 | 中華 |
伴敏嗣 | 洋食 |
織田雄太 | 中華 |
コピペ用。皆さんA1からコピペしてください
スクリプトエディタに「日本語で」手順を書く
function sendMailForLunchQuestionnaire() {� // sheetを特定� � // シート内のすべてのデータを取得する�� // chinese, japanese, western っていうカウンタに数えた結果を入れていこう� � // 1行ずつ、B列をみて、chinese, japanese, westernのどれかに1を足していく� � // 全部数え終わったらメール送信する�}
日本語で書く
function sendMailForLunchQuestionnaire() {� // sheetを特定� � // シート内のすべてのデータを取得する�� // chinese, japanese, western っていうカウンタに数えた結果を入れていこう� � // 1行ずつ、B列をみて、chinese, japanese, westernのどれかに1を足していく� � // 全部数え終わったらメール送信する�}
そもそもこれが浮かばないよ!
という方、大丈夫。当たり前です。
プログラムに関わらず、同じような経験をしたことがあれば、次に出会った時にだいたい予想できるでしょ?それと同じ。いっぱい書いてください。
日本語で書く
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を足していく� // 全部数え終わったらメール送信する�}
日本語で書く
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を足していく� // 全部数え終わったらメール送信する�}
「シート内のすべてのデータ」
というのはコレのこと
そう、二次元配列だね!
var data = [
[名前, 食べたいもの],
[沼田悠花, 中華],
[室井千代乃, 和食],
[中澤和歌子, 洋食],
[石本春夫, 洋食],
[菅谷優子, 洋食],
[米山英明, 洋食],
[大和田敏嗣, 和食],
[倉持英司, 中華],
[伴敏嗣, 洋食],
[織田雄太, 中華]
];
そう、二次元配列だね!
var data = [
[名前, 食べたいもの],
[沼田悠花, 中華],
[室井千代乃, 和食],
[中澤和歌子, 洋食],
[石本春夫, 洋食],
[菅谷優子, 洋食],
[米山英明, 洋食],
[大和田敏嗣, 和食],
[倉持英司, 中華],
[伴敏嗣, 洋食],
[織田雄太, 中華]
];
dataという配列
data[0]
data[1]
data[2]
data[5][1]
デバッグモードでも中身は確認できます
(1) ブレイクポイント
(2) デバッグ実行
→ブレイクポイントでプログラムが止まる
(3) その時点での変数の中身が見える。
例) data[1][1]が “中華” だと分かる
二次元配列を一つずつ処理する
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]);� }� � // 全部数え終わったらメール送信する�}
欲しいデータを取り出す
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]);� }� � // 全部数え終わったらメール送信する�}
ログの結果
これをカウントする
(補足) for内でやってること
var data = [
[名前, 食べたいもの],
[沼田悠花, 中華],
[室井千代乃, 和食],
[中澤和歌子, 洋食],
[石本春夫, 洋食],
[菅谷優子, 洋食],
[米山英明, 洋食],
[大和田敏嗣, 和食],
[倉持英司, 中華],
[伴敏嗣, 洋食],
[織田雄太, 中華]
];
�for (var i = 1; i < data.length; i++) {� Logger.log(data[i][1]);�}�
iが1の時
data[1]
(補足) for内でやってること
var data = [
[名前, 食べたいもの],
[沼田悠花, 中華],
[室井千代乃, 和食],
[中澤和歌子, 洋食],
[石本春夫, 洋食],
[菅谷優子, 洋食],
[米山英明, 洋食],
[大和田敏嗣, 和食],
[倉持英司, 中華],
[伴敏嗣, 洋食],
[織田雄太, 中華]
];
�for (var i = 1; i < data.length; i++) {� Logger.log(data[i][1]);�}�
iが2の時
data[2]
(補足) for内でやってること
var data = [
[名前, 食べたいもの],
[沼田悠花, 中華],
[室井千代乃, 和食],
[中澤和歌子, 洋食],
[石本春夫, 洋食],
[菅谷優子, 洋食],
[米山英明, 洋食],
[大和田敏嗣, 和食],
[倉持英司, 中華],
[伴敏嗣, 洋食],
[織田雄太, 中華]
];
�for (var i = 1; i < data.length; i++) {� Logger.log(data[i][1]);�}�
iが3の時
data[3]
(補足) for内でやってること
var data = [
[名前, 食べたいもの],
[沼田悠花, 中華],
[室井千代乃, 和食],
[中澤和歌子, 洋食],
[石本春夫, 洋食],
[菅谷優子, 洋食],
[米山英明, 洋食],
[大和田敏嗣, 和食],
[倉持英司, 中華],
[伴敏嗣, 洋食],
[織田雄太, 中華]
];
�for (var i = 1; i < data.length; i++) {� Logger.log(data[i][1]);�}�
iが3の時
data[3]
このとき
data[3][1]には
"洋食"が入ってる
中華、和食、洋食をカウントするには?(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 に代入しとく
中華、和食、洋食をカウントするには?(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だね
(補足)教えてなかった 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文というのもある。
詳しくは調べてみてね!
ひとまずここまでの全体コード(下のノート欄にあるよ)
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);� � // 全部数え終わったらメール送信する�}
ここまでで「集計する」ができた
メール本文を作成して、メールを送る
// 全部数え終わったらメール送信する
// メールの作成
var body = 'アンケート結果は\n' +
' -中華' + chinese + '人\n' +
' -和食' + japanese + '人\n' +
' -洋食' + western + '人\n' +
'でした。';
var to = '自分のメアドを書いてください';
var subject = 'ランチアンケートの結果です';
// メール送信
GmailApp.sendEmail(to, subject, body);
メール本文を作成して、メールを送る
// 全部数え終わったらメール送信する
// メールの作成
var body = 'アンケート結果は\n' +
' -中華' + chinese + '人\n' +
' -和食' + japanese + '人\n' +
' -洋食' + western + '人\n' +
'でした。';
var to = '自分のメアドを書いてください';
var subject = 'ランチアンケートの結果です';
// メール送信
GmailApp.sendEmail(to, subject, body);
メールの「本文」を作ってる
メール本文を作成して、メールを送る
// 全部数え終わったらメール送信する
// メールの作成
var body = 'アンケート結果は\n' +
' -中華' + chinese + '人\n' +
' -和食' + japanese + '人\n' +
' -洋食' + western + '人\n' +
'でした。';
var to = '自分のメアドを書いてください';
var subject = 'ランチアンケートの結果です';
// メール送信
GmailApp.sendEmail(to, subject, body);
宛先(to)と件名(subject)
を作ってる
メール本文を作成して、メールを送る
// 全部数え終わったらメール送信する
// メールの作成
var body = 'アンケート結果は\n' +
' -中華' + chinese + '人\n' +
' -和食' + japanese + '人\n' +
' -洋食' + western + '人\n' +
'でした。';
var to = '自分のメアドを書いてください';
var subject = 'ランチアンケートの結果です';
// メール送信
GmailApp.sendEmail(to, subject, body);
(ssではなく)Gmailアプリを呼び出して、
sendMailという関数を使っている。
この関数に引数としてto, subject, body を渡すと、
そのとおりにメールを送信してくれるという関数
このスライドのメモ欄にコード貼っときます↓
実践での注意点
こういうことが起こると正しく動作しなくなるよ、の例
→実務で使う場合に問題になる!
対策例
私がよくやるのは「意図したようなフォーマットになってることをチェックするスクリプト」を書いて、エラーがあったら知らせる(msgBoxやメール)
機能追加 課題1 (任意)
集計結果をメールではなく、
スプレッドシートに書き出すようにする。
機能追加 課題2 (任意)
男女別にも結果を出力したい
こんな感じ↓
アンケート結果は� -中華3人� -和食2人� -洋食5人�
<内訳>
男性
-中華2人
-和食1人
-洋食3人
女性
-中華1人
-和食1人
-洋食2人
名前 | 食べたいもの | 性別 |
沼田悠花 | 中華 | 女 |
室井千代乃 | 和食 | 女 |
中澤和歌子 | 洋食 | 女 |
石本春夫 | 洋食 | 男 |
菅谷優子 | 洋食 | 女 |
米山英明 | 洋食 | 男 |
大和田敏嗣 | 和食 | 男 |
倉持英司 | 中華 | 男 |
伴敏嗣 | 洋食 | 男 |
織田雄太 | 中華 | 男 |
スプレッドシート実践 その2
(データをまとめて複数セルに出力する)
複数の値を入力する実験
「複数の値実験」というシートを追加してください。
下記のような出力をするプログラムを作りたいとします。
スクリプトファイルを追加してください
ファイル名は「複数の値実験」にしてください。
これでもやりたいことは実現できる
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('かかか');�}�
だけど問題があります。
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に対して
アクセスしている
どゆこと?
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界
実行速度の比較の参考はここ
Google Apps Scriptのスプレッドシート読み書きを格段に高速化をする方法
https://tonari-it.com/gas-spreadsheet-speedup/
21秒かかったスクリプトが0.4秒になった例
GASには制限があるのです。
詳細はここ https://developers.google.com/apps-script/guides/services/quotas
実務上で一番問題になるのが「実行時間の上限が6分まで」という制限。
これを超えるとプログラムが途中終了されます。
→よって、実行時間は短いほうがいい。
一度に書き出す例 (コピーして実行してみよう)
function copySomeValue2() {� var ss= SpreadsheetApp.getActiveSpreadsheet();� var sheet = ss.getSheetByName('複数の値実験');� � var output = [� ['あああ','いいい','ううう'],� ['えええ','おおお','かかか']� ];� � sheet.getRange('A1:C2').setValues(output);�}
ポイント1:データをニ次元配列で作成する
function copySomeValue2() {� var ss= SpreadsheetApp.getActiveSpreadsheet();� var sheet = ss.getSheetByName('複数の値実験');� � var output = [� ['あああ','いいい','ううう'],� ['えええ','おおお','かかか']� ];� � sheet.getRange('A1:C2').setValues(output);�}
出力したいデータたちを
二次元配列で表現する
ポイント2:出力範囲を指定してsetValues
function copySomeValue2() {� var ss= SpreadsheetApp.getActiveSpreadsheet();� var sheet = ss.getSheetByName('複数の値実験');� � var output = [� ['あああ','いいい','ううう'],� ['えええ','おおお','かかか']� ];� � sheet.getRange('A1:C2').setValues(output);�}
出力範囲を正確に指定する
setValuesに二次元配列を渡す
(ハマリポイント) データ数は揃える必要がある!
[
['aa', 'bb', 'cc'],
['dd', 'ee', '']
]
最大の列数にあわせる
つまり、セルに書き出したいデータは
始めから2次元配列の形で用意しておくと
処理がラク!
スプレッドシート実践 その3
(行の末尾に追加したい)
さっきの続き
データは随時追加されていきます。
その時点の「一番下に追加したい」というニーズ、あるよねー。
こうかもしれないし
こうかもしれない
一番下に追加したい
例えばこうする
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);�}
実行結果
最終行の取得
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);�}
ココがポイント
出力範囲を指定する
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 してる)
出力する
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’ みたいな文字列をつくる
スプレッドシート課題 (必修)
(別シートに出力する課題)
別のSSのシートにコピーする
「スプレッドシートA」のシート1から
「スプレッドシートB」のシート2に
「複数の値を一度にコピーする」方法を紹介します。
1)いま使っているSSに「全体シート」を追加してください。
2)自分のフォルダの中に「新しいSS」を作成して
「自チームシート」を作成してください。
こうなります
元のSSにシート追加
新しいSSを作成
使うデータはこれをコピーしてください
全体シート | | | |
| | 予算 | 結果 |
部署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 |
やりたいことはこれ(自チーム=部署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 |
「自チーム」のSSにスクリプトを追加します
「自チーム」のSSの値を集計し、全体のSSにコピーしに行く、をやります。
自チームのSSにスクリプトを追加してください。
プロジェクト名は「SS間コピー」で。
関数名は「copyToAllSheet」で。
SS間コピー
ここから課題
下記の続きを書いて、部署Bの情報を全体シートに記入できるようにしなさい
function copyToAllSheet() {� var myTeamSS = SpreadsheetApp.getActiveSpreadsheet();� var mySheet = myTeamSS.getSheetByName('自チームシート');� � var allSS = SpreadsheetApp.openById('xxxxx下記の調べ方参照 xxxxx');� var allSheet = allSS.getSheetByName('全体シート');�
// ここからプログラムを書く��}
今回の新しいこと
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);�}
処理の流れイメージ
全体シート | | | |
| | 予算 | 結果 |
部署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する
(任意課題) 応募者の中から抽選で10名に商品が当たる
新しいシートを作成して、シート名を「抽選」にしてください。
左記のように、「ID、名前」のダミーデータを200人以上作ってください。
(ダミーデータは 疑似個人情報生成 を利用しました)
応募者の中からランダムで10人の「当選」を決める
当選者のC列に「当」って出力する
(過去にやった「おみくじ」を参考に!)
Slack連携
新しいスクリプトファイルを作成
名前を
「slack通知」
にしてください
(全体シートのほうに)
Slack連携の手順
↑ここがわかりやすいです。
手順としては
これだけ。
Slack連携の手順
↑ここがわかりやすいです。
手順としては
これだけ。
レクチャではすでに設定をしておきました
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);�}
(※) アイコンはここらへんから選ぶ
青字の部分を変更して実行してみよう
incoming webhooks のURL
実際はこんな感じで使う
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);�}
こっちの関数でなにかさせる
Googleフォーム
GoogleフォームでGASといえば圧倒的にこれ!
フォームに送信があったらメールで通知してほしい
...でもそういう機能がついたみたいデス
昔はこんなん無かったよ
でもslack通知はデフォ機能じゃできない!→やろう
自分のフォルダにフォームを作成
「新規 → Googleフォーム」
※このGASはフォームに紐付きます
適当に質問つくってください
1.質問をつくって
3.スクリプトエディタを開く
2.ここから
ひとまずコピペする
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);�}�
ここだけ変えてみよう
トリガーが必須
トリガーを設定することで、このGASがいつ実行されるか指定できます
submitForm
「プレビュー」→ 回答してみよう
コードの解説
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の略)の中に
送信されたフォームの情報が詰まってる
こうすることで「質問」「回答」のペアが、
設定された数の分だけ取得できる
出力するメッセージを作る
GmailをGASで操作する
新しいスクリプトファイルを作成
名前を
「Gmail」
にしてください
(スプレッドシートの方で)
Gmailサービスの構造
GmailApp
└Thread
└ Message
└ Attachment
Messageを取り出す時
GmailApp
└Thread
└ Message
└ Attachment
1.Threadを検索する
2.1のThreadの中からMessageを取り出す
Thread検索の前に、Gmail検索使いこなしてる?
ここをうまく使おう。
例えば
subject:サンプル newer_than:20d
これを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の条件でメール検索
最初の一通だけ取得したい
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通目だけほしいことがあるよね。
(外部からの通知メールとか)
最初の一通だけ取得したい
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] が最初のメッセージです
Gmailでもっといろんなことがしたい人は
【GAS】Gmailに送られた過去のメールから特定条件のメールを検索して取得するhttps://tonari-it.com/gas-gmail-search-thread/
実務で使うパターン
実務で使うパターン (任意課題)
実務で使うパターン (任意課題) ヒント
もっといいロジックがありそう
他にもgoogleのサービスはある
ここまでで
を扱いましたが、他にも業務で使いそうな
...もGASで扱えます。
正規表現
(文字列を扱う時に役に立ちます)
新しいスクリプトファイルを作成
名前を
「正規表現」
にしてください
正規表現とは?
Regular Expression 日本語で「正規表現」
いくつかの文字列を一つの形式で表現するための表現方法
例1: 郵便番号を表現するパターン
\d{3}-?\d{4}
正規表現とは?
Regular Expression 日本語で「正規表現」
いくつかの文字列を一つの形式で表現するための表現方法
例1: 郵便番号を表現するパターン
\d{3}-?\d{4}
\d 半角数字
{n} 直前の文字をn回繰り返す
? 直前の文字が0回か1回ある
今は「へぇー...」
くらいでOK!
どんな時に使うか?
例)文字列の中に電話番号が入っていたら、それを*****に置き換える。
-------------------------------------
こんにちわ。�私の電話番号を教えますね。��080-0000-0000��です。よろしくー。
コピペして実行(電話番号マスキングサンプル)
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);�}�
コード解説
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);�}�
正規表現(パターン)を定義してあげる
/ と / で挟むのがルール
コード解説
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)
という命令
電話番号を複数書いてみると。。。(゜A゜ノ)ノ
�こんにちわ。�私の電話番号を教えますね。��080-0000-0000�090-1111-1111��です。よろしくー。
2つ目以降は置換されない
コピペして実行
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 (すべてのマッチを探すフラグ)
この指定がないと、最初にマッチしたものだけが対象になる
他にもこんな使い方1
他にもこんな使い方2
1.Gmailで受信したメール
ータイトル
ー見出し
ーURL
を1組にして複数個切り出してスプレッドシートに自動で書き出す。とか。
正規表現にはこれが便利
概要を知りたい
自分が書いた正規表現がどういう意味なのか、何にマッチするのか知りたい
JavascriptのRegExpについて知りたい
Moment(日付)
(ライブラリ) Moment
日付を扱う組み込みオブジェクトとして「Dateオブジェクト」が用意されている。
だけどこれがちょっと使いにくい。
日付・時刻をもっと簡単に扱えるように「Moment.jsライブラリ」を作ってくれた人がいる。
それを使うと、Dateを使うよりラクに日付・時刻を扱えるので、こっちを使おう。
が公式
Momentライブラリを追加する
https://tonari-it.com/gas-moment-js-moment/
Momentライブラリを追加する
https://tonari-it.com/gas-moment-js-moment/
プロジェクトキー:MHMchiX6c1bwSqGM1PZiW_PxhMjh3Sh48
日付の計算をしてみます
「日付」というシートを作って、下記の表を作ってください。
(期限日は自由に日付をいれてください)
今日から期限日まで、何日あるのか、
を計算するプログラムを書きます。
例えば3日前にリマインドメールを送る
みたいな使い方。
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/
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',� '[リマインダ]期限が近いタスクがあります',� '期限が迫っているタスクがあるので確認よろしく!');� }�}
自分のメアド
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()
で、「現時刻」を意味するオブジェクトができる。
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」で検索!!
UrlFetch
(資料未完成)
外部サイトにHTTPリクエストを送ることができます!
組み込みオブジェクト
背景がグレーのスライドは
自分が必要になったときに「こういうものがあるんだ」「こんなワードで調べられるんだ」
を知っておいてもらえればOK。あとは実務で必要になるし。
新しいスクリプトファイルを作成
名前を
「組み込みオブジェクト」
にしてください
組み込み関数とは
「最初から用意されている関数」のこと。
よく使われる道具がすでに用意されている、ということ。
よく使うやつ
使わないかもしれないけど知っておけ、なやつ
ここでは...
「使い方の調べ方」を覚えてください。
組み込み関数は膨大にあります。私も覚えてません。
「こんな関数あったな」とか「こういうことができる関数あるかな」を
自分で調べてコピペして使う、がキホンです!
例えば「Javascript String」で検索すると詳しく教えてくれるサイトがいっぱいある。注意点としては「新しい情報かどうか」(Javascriptも進化しているので古いと使えないモノがある)
String(文字列)
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 );�}
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に置き換える
()内の文字が最後に出てくるインデックスを返す
覚えておくことはこれ
細かいところは覚えなくていい。
だけど「文字列を操作する関数」としてどんなものがあるのか、は覚えておく。
文字列に対して
をしたい → 調べる
調べ方の実演 indexOf
見たのはここ
↓
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/indexOf
まずは「構文(書き方のルール)」を見る
「引数」と「戻り値」を確認
サンプル見ちゃうのが早いよね
「使い方」「やりたいこと」で調べる
「Javascript indexOf 使い方」とか、
「javascript 文字列 切り出す」とか、
「Javascript 文字 置換」とか。
わからなかったら検索する。
検索の仕方を知ることと、使い方の読み方が大事。
初心者はリファレンスでくじけるけど慣れてないだけ。リファレンスは味方です.
例えば。。。
ある文字列の中に、特定の文字列が含まれるかどうかを調べたい。
<サンプル文章>
日本国民は、正当に選挙された国会における代表者を通じて行動し、われらとわれらの子孫のために、諸国民との協和による成果と、わが国全土にわたつて自由のもたらす恵沢を確保し、政府の行為によつて再び戦争の惨禍が起ることのないやうにすることを決意し、ここに主権が国民に存することを宣言し、この憲法を確定する。
この文章の中に「自由」という文字列が存在するかどうか、を調べるプログラムを作りたい。
Google先生に聞いちゃうと早いよね
indexOfでできるらしい
function stringObject2() {�� var text = '日本国民は、正当に選挙された国会における代表者を通じて行動し、われらとわれらの子孫のために、諸国民との協和による成果と、わが国全土にわたつて自由のもたらす恵沢を確保し、政府の行為によつて再び戦争の惨禍が起ることのないやうにすることを決意し、ここに主権が国民に存することを宣言し、この憲法を確定する。';� var word = '自由';� � if (text.indexOf(word) !== 1) { //含まれていない場合に-1を返す、を利用する� Logger.log(word + 'が含まれている');� } else {� Logger.log(word + 'が含まれていない');� }�}
Array(配列)
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 は () がつかない。関数じゃなくプロパティだから。
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);�}�
配列といえば「要素をとりだして処理する」
// 要素一つずつを取り出して、関数を実行する(コールバック関数と呼ぶ)�// 関数の中で要素を使えるように「仮引数」を用意する(名前は自由)�function arraySample3() {� var characters = ['悟空', 'ピッコロ', 'クリリン', 'ベジータ'];� � characters.forEach(function(name, index, array) {� Logger.log(index + ': Hello ' + name +'!');� });�}
forEach 解説
// 要素一つずつを取り出して、関数を実行する(コールバック関数と呼ぶ)�// 関数の中で要素を使えるように「仮引数」を用意する(名前は自由)�function arraySample3() {� var characters = ['悟空', 'ピッコロ', 'クリリン', 'ベジータ'];� � characters.forEach(function(name, index, array) {� Logger.log(index + ': Hello ' + name +'!');� });�}
characters配列の「要素一つずつ」に対して、function() を実行するよ。
関数の中では、要素の値は name, インデックスは index, 元の配列は array
という変数で扱うよ。ということ。(仮引数は自分でつけていい)
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 という「反復メソッド」が用意されてます。
Math(数学的処理)
Math (コピペして実行してみよう)
function mathSample() {� Logger.log(Math.ceil(10.5)); //小数点以下を切り上げ� Logger.log(Math.floor(10.5)); //小数点以下を切り捨て� Logger.log(Math.round(10.5)); //小数以下を四捨五入して「整数」にする�}
ログに出力される小数点は「無かったこと」にしてください。
スクリプトエディタの仕様で、内部的には「整数」になってる
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」にする、ができない。
小数第三位で四捨五入、のサンプル
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);�}
おみくじサンプル(再掲+解説)
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 になる
(小数点以下を切り捨てるということ)
他にもMath
くわしくは下記にあります。
(こゆのがあるんだな、ということを覚えておいて下さい)
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Math
レクチャーの最後に
残念ながらこれだけじゃ実現できない
ここに載っていること+自分で調べたことを
「組み合わせる」ことで
やりたいことを実現するフェーズに入ります。
プラモデルはパーツがあって、
設計書通りに組み立てたら、完成します。
プログラムはパーツがあって、
設計書通りに組み立てたら、完成する。。。
わけじゃない
ありもののパーツを見つけてくる。
いいパーツがなければ自分で作る。
組み立ての順番も自分で考える
プログラム初学者の2大「わからない」
→「人がその処理をしたらどういう順番で何をするか」を紙に書く
→調べることで解決できることが多い
→言語の仕様や関数の使い方
なるべく「小さな」「単純な」処理に分解する
ここは知ってる/知らないの世界なので
「自分で調べる」「分かる人に聞く」
で解決できる
効率よくコードを書くために
「すでに用意されている便利な道具(関数や他人のコード)」をうまく使おう。
「自分で生み出すスキル」よりも、「あるものを使うスキル」の方が大事。
そのためには「何があるのかを調べるスキル」が大事
ここまではプログラミングの中のごく一部
その先に
コードが継続して利用され続けるために
将来の問題点
将来の問題点
「自分だけがわかればいい」だと業務継続ができなくなる可能性が上がる
�「GASを書ける人が複数人いる+他の人が見ても理解できるコードである」
将来の問題点
結果は同じでも「効率のいい書き方」がある (ない場合もあるけど)�遅い場所を突き止めて、改善していく(パフォーマンス改善)
継続して使われ続けるための知識・ノウハウ
卒業課題
卒業課題
レクチャーの最初に「(宿題2)何を効率化したいのか?を決めること」をおこなってもらいました。
そのままでもいいですし、レクチャを受けてやってみたいことが変わってもいいです。
どんな小さくでもいいので、自分の業務を効率化・自動化できるGASを書いてください。
「やった気になる」ではなく「実際に完成させる」までやることが大事です!