見出し画像

【GAS】初級の復習 その5(スプレッドシート)

▼こちらの続き

GAS初心者講座の復習もいよいよ最終回まできた。テーマは実践的にスプレッドシートの操作に入る。スプレッドシートではすでにGASを結構使っているので、ぶっちゃけ分かっていることばかりだろうと思っていた。(フラグ)

スプレッドシート・シートの取得

スプレッドシートの取得方法は3つ。

・アクティブなスプレッドシートを取得
 SpreadsheetApp.getActiveSpreadsheet()
・URLで取得
 SpreadsheetApp.openByUrl(URL)
・IDで取得
 SpreadsheetApp.openById(ID)

シートの取得方法も3つ。

・シート名で取得
 Spreadsheetオブジェクト.getSheetByName(シート名)
・配列を取得しインデックスで指定
 Spreadsheetオブジェクト.getSheets()
・アクティブなシートを取得
 SpreadsheetApp.getActiveSheet()

この辺はさすがに毎回書いているので分かる。

アクティブなスプレッドシートの全てのシート名をログ出力するスクリプトを作ってみましょう。
function myFunction5_03() {
 const ss = SpreadsheetApp.getActiveSpreadsheet();
 const sheets = ss.getSheets();
 for (const sheet of sheets) {
   console.log(sheet.getName());
 }
}

スプレッドシートのシートが多くなると探しにくくなるので、このようなスクリプトでシート名とURLを書き出してインデックスシートみたいなのを作れるのは便利。

実際に最近仕事で使っているプロジェクト系のスプレッドシートでも作ってみた。↓

function indexSheet() {
 const ss = SpreadsheetApp.getActiveSpreadsheet();
 const indexSheet = ss.getSheetByName(`インデックス`);
 const sheets = ss.getSheets();
 const url = `https://docs.google.com/spreadsheets/d/***スプレッドシートID***/edit#gid=`;

 for (let i = 1; i < sheets.length; i++) {
   indexSheet.getRange(i + 1, 1).setValue(i);
   indexSheet.getRange(i + 1, 2).setValue(sheets[i].getName());
   indexSheet.getRange(i + 1, 3).setValue(`${url}${sheets[i].getSheetId()}`);
 }
}

function onEdit(){
 indexSheet();
}

こんな感じになる。↓ 

スクリーンショット 2021-07-16 6.51.17

シート名にリンクを貼れればもっとスマートだろうけどすぐにやり方がわからなくて、調べる時間もなかったので追々直していく。とりあえず目的通りに動けばOK。onEditを関数を使うことで、自動で反映されるのが地味に感動ポイント。

セル範囲の取得・値の取得/入力

値の取得(getValue)/値の入力(setValue)は単数系ではあまり使わないので割愛。二次元配列で範囲・値を取得し、入力する場合は配列サイズが合わないとエラーが出るので以下のように書く。当時はマジックナンバーで書いてたなぁ。

getRange(行番号, 列番号, values.length, values[0].length)

コピーする(CopyToメソッド)

Rangeオブジェクト.copyTo(destination)

講座では触れていなかったが、直近やっていた初心者講座の宿題回答を参考に拝見したらある宿題でこのメソッドを使っている回答があって便利そうだなと思ったのでメモ。コピー元と貼り付け先の範囲が異なっていても使える。引数(destination)には貼り付けする左上のセルを指定すればOK。ノンプロ研は自分が参加していない講座でもSlackチャネルを覗けるのでありがたい。| _•)チラッ

以下のA1からC4のセル範囲をE3を基点とするセル範囲にコピーするスクリプトを作りましょう。

画像1

function myFunction5_11_2() {
 const sheet = SpreadsheetApp.getActiveSheet();
 const copyRange = sheet.getRange(`A1:C4`);
 const pasteRange = sheet.getRange(`E3`);

 copyRange.copyTo(pasteRange);
}

シートの最終行に追加(AppendRow)

Sheetオブジェクト.appendRow(配列)​

便利そうだけど意外と使っていないAppendRowメソッド。引数には一次元配列を渡すことがポイント。二次元配列を渡すと変な値がスプレッドシートに入力される。↓

画像2

以下の配列を引数として受け取り、シートの最終行にデータを追加する関数を作りましょう。
[name, age, favorite]
function myFunction5_14_02() {
 const sheet = SpreadsheetApp.getActiveSheet();
 const array = [`Ikko`, 40, `Music`];

 const appendRow = array => sheet.appendRow(array);
 appendRow(array);
}

こういうのは結構使えそうかな。値をバラバラに受け取っても、オブジェクトで受け取っても、1次元配列に格納し直せばいい。

noteでは一部しか載せていないけれど、初心者講座の復習では全ての宿題に再度チャレンジしている。関数を作る問題は全てアロー関数でもスクリプトを書くようにしていて、やっとスラスラできるようになってきた!

Arrayオブジェクト

スプレッドシートの操作の中で基本的なArrayオブジェクトも教わっていたけど、初級の復習をするまでそもそもArrayオブジェクトとは何ぞや、っていう概念が分かってなかったなぁ。

・lengthプロパティ
配列の要素を取得する。

Arrayオブジェクト.length  


・includesメソッド 
配列内を検索して値が存在するかどうかをブール値で返す。

Arrayオブジェクト.includes(値)


・indexOfメソッド 
配列内を検索してその位置を取得する。値が存在する場合はインデックス(整数)、存在しない場合は-1が返ってくる。配列なので、インデックスは0から始まる。また、存在しない場合はfalseが返ってくるのではなく、-1というところもポイント。if文とかで判定する場合はブーリアンではなく、数値型で判定するようにしないといけない。メモメモ。

Arrayオブジェクト.indexOf(値)
function myFunction6_01() {
 const members = [`Bob`, `Tom`, `Jay`];
 console.log(members.indexOf(`Tom`)); //1
 console.log(members.indexOf(`Ivy`)); //-1
}


・flatメソッド
配列の次元を減らす(2次元→1次元)。引数にInfinityを入れると強制的に一次元配列になる。

Arrayオブジェクト.flat()
function myFunction6_03() {
 const numbers = [[10], [30], [20], [40]];
 console.log(numbers.flat()); //[10, 30, 20, 40]
} 

ところで、flatメソッドだけ入力補完(コンテンツアシスト)が毎回出ない気がするのだけれど、なんでだろう。分かる人(つじけ先生)コメントください。

画像4


・pushメソッド
配列の最後尾に要素を追加する。元の配列が変わってしまう破壊的メソッド。

Arrayオブジェクト.push(値)


・shiftメソッド
配列の先頭から要素を抜き出す。抜き出した要素が戻り値となり、引数はない(入れない)。こちらも破壊的メソッド。

Arrayオブジェクト.shift()

pushとshiftの動きが分かるコード例。↓

function myFunction6_05_02() {
 const values = [`A`, `B`, `C`, `D`];
 console.log(values); //[ 'A', 'B', 'C', 'D' ]

 values.push(`E`); 
 console.log(values); //[ 'A', 'B', 'C', 'D', 'E' ]

 const firstValue = values.shift();
 console.log(firstValue); //A
 console.log(values); //[ 'B', 'C', 'D', 'E' ]
}

これは分かりやすく一次元配列にしているけど、二次元配列でshiftメソッドを使うと、見出し行を除くことができる。

破壊的メソッドは元の配列を変えてしまうので、スプレッド構文で複製を作っておくと良いとのこと。スプレッド構文は中級でもやったけど、うろ覚え。

...Arrayオブジェクト

↑Arrayさん、なんか困っちゃったのかな...みたいな感じ。

function myFunction6_05_03() {
 const numbers = [10, 30, 20, 40];
 console.log(numbers); // [10, 30, 20, 40]
 console.log(...numbers); //10 30 20 40

 const copyNumbers = [...numbers];
 numbers.shift();
 console.log(numbers); //[ 30, 20, 40 ]
 console.log(copyNumbers); //[ 10, 30, 20, 40 ]
}

スプレッド構文は配列の個々の要素を展開するので、他の変数に複製して格納するときは[]が必要になる。ふむふむ。

処理時間の測定

実行している時間を測定する。その前に、consoleってめっちゃ使うし、なんなら最初の'Hello World!'からやっているけど、そもそも何者なのかが分かっていない。GAS本を見たところ、クラスと書いてある。つまりこれもオブジェクトで、logとかtimeとかtimeEndもメソッドなのね。ほぉぉぉおぉおお。

あまり使う機会はなさそうだけど、セットで書く。timeEndはログも合わせて出してくれる。便利。

タイマースタート console.time(ラベル)
タイマー終了・ログ出力 console.timeEnd(ラベル)
function myFunction6_07() {
 const label = '配列で処理した場合';
 console.time(label);
 const values = SpreadsheetApp.getActiveSheet().getRange(1, 1, 1000, 5).getValues();
 for (const record of values) {
   for (const value of record) {
   }
 }
 console.timeEnd(label); //配列で処理した場合: 148ms
}

初心者GAS講座の復習終わり

ということで、全6回(計12時間)分の初心者GAS講座の復習を終えた。想像していた以上に忘れていたことや分かっていなかったことばかりで、自分でも驚いた。特に概念としてよく分かっていなかったオブジェクト・プロパティ・メソッドについて、たぶん正しく理解できたことや、苦手だった関数(しつこいけど特にアロー関数)についても演習や宿題を解き直すことで苦手意識が全くなくなった。目標としていた基本から改めて理解するというところは達成できたと思う。

中級の復習編へ続く(続けるように頑張る)。







この記事が気に入ったらサポートをしてみませんか?