episode4 GAS【IFとループ】ヒソカの念チェック「HUNTER×HUNTERで覚えるGoogle Apps Script」

この記事のシリーズを読むことで、アニメHUNTER×HUNTER(ハンターハンター)を通してGAS(Google Apps Script)の最初の一歩が学べます。

この記事では、

・GASによるIF分岐とループでヒソカと同じ念系統か調べる

・配列で処理時間を短縮

・最後の行をgetLastRow()で求める

SpreadSheetApp→アクティブシート→アクティブセルと階層を辿ることによって処理時間がかかってしまうことを空の配列を用意することで解決する方法を掲載しています。

GASでは配列の扱いがとても重要になります。

ますは、前回(episode3)の復習をします。

・セルA1からB4にキャラクター名を入力する関数と消去する関数を作り、それぞれをボタンに登録しました。

//アクティブなスプレッドシートを選択するグローバル領域
const ss=SpreadsheetApp.getActiveSheet();


//スプレッドシートにキャラクターの名前と念系統の入った配列を出力する
function nenArray(){

  //二次元配列hhにキャラクターの名前と念系統を格納
  const hh = [
      ['ゴン','強化系'],
      ['キルア','変化系'],
      ['クラピカ','具現化系'],
      ['レオリオ','放出系']
    ];
  
  //配列hhをログに出力
  console.log(hh);

  //行の長さを調べる
  console.log(hh.length);

  //列の長さを調べる
  console.log(hh[0].length);

  //二次元配列hhを格納するために、スプレッドシートの4行2列を確保して出力する
  ss.getRange(1,1,hh.length,hh[0].length).setValues(hh);

}


//出力した配列を消去する
function myClear() {

  //出力した配列をgetDataRangeを使って取得して消去する
  ss.getDataRange().clear();

}

実行するとこの様になっていると思います。

ヒソカの念は「変化系」でキルアと一緒です。


今回はIF文を使って、ゴンからレオリオまでのキャラの念が、ヒソカと同じ変化系かどうか調べます。

ゴンは「強化系」なので「変化系」とは異なる為、条件が当てはまらないelseへと分岐します。

ゴンの念が入力されているセル「B1」は「1行目の2列目」ですので、(行,列)で書くと(1,2)と書くことも出来ます。

処理はelseになる為、隣のセルである「C1 (1,3)」には「XXX」と入力されます。

//アクティブなスプレッドシートを選択するグローバル領域(共通の処理)
const ss=SpreadsheetApp.getActiveSheet();


//【ゴン】がヒソカと同じ念系統か判定する関数
function Hisoka() {
  let nen = ss.getRange(1,2).getValue(); //ゴンの念を取得
  console.log(nen);
  
  //【ゴン】の念はヒソカと同じ「変化系」か?
  if(nen=='変化系'){
    ss.getRange(1,3).setValue('ヒソカと一緒');
  }else{
    ss.getRange(1,3).setValue('XXX'); //違うからこっちに分岐
  }
}

ログ出力です。
ゴンの念系統「強化系」が出力されました。

スプレッドシートです。
C1に「XXX」と入りました。


次に、「キルア」を調べます。

キルアは「変化系」なので、「ヒソカ」と同じという条件が当てはまり「ヒソカと一緒」と表示されます。

//アクティブなスプレッドシートを選択するグローバル領域(共通の処理)
const ss=SpreadsheetApp.getActiveSheet();


//【キルア】がヒソカと同じ念系統か判定する関数
function Hisoka() {
  let nen = ss.getRange(2,2).getValue(); //キルアの念を取得
  console.log(nen);
  
  //【キルア】の念はヒソカと同じ「変化系」か?
  if(nen=='変化系'){
    ss.getRange(2,3).setValue('ヒソカと一緒'); //同じだからこっちに分岐
  }else{
    ss.getRange(2,3).setValue('XXX'); 
  }
}

ログ出力です。

スプレッドシートです。
キルアの念はヒソカと同じなので、セルC2に「ヒソカと一緒」と入力されました。


次に、「クラピカ」を調べます。

クラピカは「具現化系」なので、「変化系」とは異なる為、条件が当てはまらないelseへと分岐します。

//アクティブなスプレッドシートを選択するグローバル領域(共通の処理)
const ss=SpreadsheetApp.getActiveSheet();


//【クラピカ】がヒソカと同じ念系統か判定する関数
function Hisoka() {
  let nen = ss.getRange(3,2).getValue(); //クラピカの念を取得
  console.log(nen);
  
  //【クラピカ】の念はヒソカと同じ「変化系」か?
  if(nen=='変化系'){
    ss.getRange(3,3).setValue('ヒソカと一緒'); 
  }else{
    ss.getRange(3,3).setValue('XXX'); //違うからこっちに分岐
  }
}

ログ出力です。

スプレッドシートです。
ヒソカとは念が異なるので、C3に「XXX」と入力されました。


最後に、「レオリオ」を調べます。
レオリオは「放出系」なので、ヒソカの「変化系」とは異なる為、条件が当てはまらないelseへと分岐します。

//アクティブなスプレッドシートを選択するグローバル(共通の処理)
const ss=SpreadsheetApp.getActiveSheet();


//【レオリオ】がヒソカと同じ念系統か判定
function Hisoka(){
  let nen=ss.getRange(4,2).getValue();  //レオリオの念を取得
  
  //【レオリオ】の念はヒソカと同じ「変化系」か?
  if(nen=='変化系'){                      
    ss.getRange(4,3).setValue('ヒソカと一緒');
    }else{
    ss.getRange(4,3).setValue('XXX'); //違うからこっちに分岐
  }
}

ログ出力です。
レオリオの「放出系」が出力されました。

スプレッドシートではC4に「XXX」と出力してelseの処理を実行しました。


ここまでで、「なんだか同じような処理をしていて、それで一部だけを変更している」と言う感覚になられたと思います。

上記のコードで「i」の部分のみを変えています。
そこで、ゴンからレオリオまでを繰り返して調べられる、Forによるループを使います。

getRange(i,2)getValue(); //キャラの念を取得 
getRange(i,3)setValue(‘ヒソカと同じか違うか’)      

実はここまでの記事で、ループのトレースを行えておりました。

追加としては、

ゴン・・・i=1
キルア・・・i=2
クラピカ・・・i=3
レオリオ・・・i=4

と、変数が出てくるぐらいです。

なぜ「i」なのか、それは、ループで慣習的に使う変数として、「i、j、k」がよく使われるからです。

このことについては、「なぜ、新人つぶしのトンパさんは、トンパさんという名前なのか」と突き詰めてしまうことの様なものなので、ループではiとかを使うんだな、程度に捉えておりましたが、やはり気になって調べた所、分かりやすい記事を見つけました。

「i, j, k」ってなに?知っておきたいfor文の変数名の由来


ゴン〜レオリオまでメンバーは4人ですので、その人数を調べるために、変数Nに「getLastRow()」(最後の行)を調べて格納します。

最後の行…getLastRow();

以上を踏まえてループとIFを使ったコードを書くと、下記の様になります。

//アクティブなスプレッドシートを選択するグローバル領域(共通の処理)
const ss=SpreadsheetApp.getActiveSheet();


//【メンバー】がヒソカと同じ念系統か判定する関数
function Hisoka() {

  const N = ss.getLastRow(); //人数は変数Nに格納。この場合は4人
  console.log(N);

  for(i=1;i<=N;i++){
    let nen = ss.getRange(i,2).getValue(); //メンバーの念を取得
    console.log(nen);
  
    //【メンバー】の念はヒソカと同じ「変化系」か?
    if(nen=='変化系'){
      ss.getRange(i,3).setValue('ヒソカと一緒'); //キルアの場合
    }else{
      ss.getRange(i,3).setValue('XXX'); //キルア以外
    }
  }
}

ログ出力です。
スプレッドシートには同様に出力されております。

この「Hisoka」をボタンの「スクリプトを割り当て」でボタンに登録します。
ボタンを右クリックして3点リーダーから登録します。


また、下記のコードで、ヒソカと念が同じかどうか調べた範囲の判定結果を削除します。

//ヒソカチェックのクリア
function HisokaClear(){
  
  //行数を取得して変数Nに人数を格納
  const N=ss.getLastRow();

  ss.getRange(1,3,N).clear();
}

一旦ここまでのコードをまとめます。
人数の行数をは判定もクリアも同じ4人でNですので、グローバル領域に移動しました。

//アクティブなスプレッドシートを選択するグローバル領域(共通の処理)
const ss=SpreadsheetApp.getActiveSheet();

//行数(人数)を取得する
const N=ss.getLastRow();
// console.log(N); 確認済みなのでコメントアウトしました。


//【メンバー】がヒソカと同じ念系統か判定する関数
function Hisoka() {

  for(i=1;i<=N;i++){
    let nen = ss.getRange(i,2).getValue(); //メンバーの念を取得
    // console.log(nen); 確認済みなのでコメントアウトしました。
  
    //【メンバー】の念はヒソカと同じ「変化系」か?
    if(nen=='変化系'){
      ss.getRange(i,3).setValue('ヒソカと一緒'); //キルアの場合
    }else{
      ss.getRange(i,3).setValue('XXX'); //キルア以外
    }
  }
}

//ヒソカチェックのクリア
function HisokaClear(){
  
  ss.getRange(1,3,N).clear();
}

紫のボタン「ヒソカチェック」に関数「Hisoka」を、灰色のボタン「ヒソ消し」に関数「HisokaClear」それぞれスクリプトを割り当てます。

これで、ボタンを使って、判定したり消したりが出来る様になりました。
現在、ヒソ消しを押して、判定の列は削除してあります。


このままでも良いのですが、GASでループを使う場合、1回1回SpreadsheetAppからアクティブシートを辿ってしまうので処理に時間がかかってしまいます。

そこで、一旦B列4行分の各メンバーの念系統を配列arrayに格納します。
配列arrayには[[‘強化系’],[‘変化系’],[‘具現化系’],[‘放出系’]]が入ります。

また、そのメンバーの念系統がヒソカの変化系と等しいかどうかの判定結果を格納する配列judgeを用意します。
配列arrayには[[‘XXX’],[‘ヒソカと一緒’],[‘XXX’],[‘XXX’]]が入ります。

それぞれの空の配列を用意しております。

//【メンバー】の念を格納する配列を宣言
  let array=[];

//変化系と等しいか判定結果を入れる配列
  let judge=[];

配列arrayを使って、念系統がヒソカと同じ変化系かどうか調べて、その判定結果を配列judgeに格納する処理にループを用います。
また、judgeに格納するときにpushを使います。

この配列を使うことによって、スプレッドシートからアクティブシートに階層を辿って行く処理時間を短縮できます。

ここまでの処理について、ログ出力のところまでのコードを掲載致しました。
配列は0から始まるので、ループの条件部分を修正しました。

i=0、i<Nと変更してあります。

また、配列judgeに入れる際、スプレッドシートに出力するのに二次元配列の形にするので、と[ ]を付けて配列に追加しております。

judge.push([‘ヒソカと一緒’]) → ifでキルアの念系統の場合

judge.push([‘XXX’]) → elseでキルア以外のメンバーの念系統の場合


その部分のコードの抜粋です。

//【メンバー】の念はヒソカと同じ「変化系」か?
    if(array[[i]]=='変化系'){
      judge.push(['ヒソカと一緒']); //キルアの場合
    }else{
      judge.push(['XXX']); //キルア以外
    }

ここまでのログ出力までのコードです。

//アクティブなスプレッドシートを選択するグローバル領域(共通の処理)
const ss=SpreadsheetApp.getActiveSheet();

//行数(人数)を取得する
const N=ss.getLastRow();


//【メンバー】がヒソカと同じ念系統か判定する関数
function Hisoka() {

  let array= [];
  let judge = [];

  //B列の各メンバーの念を配列arrayに格納
  array=ss.getRange(1,2,N).getValues();
  console.log(array);

  for(i=0;i<N;i++){
   
    //【メンバー】の念はヒソカと同じ「変化系」か?
    if(array[[i]]=='変化系'){
      judge.push(['ヒソカと一緒']); //キルアの場合
    }else{
      judge.push(['XXX']); //キルア以外
    }
  }
  console.log(judge);

}

配列arrayとヒソカの念との比較のログを出力しました。

【配列array】


【配列judge】

この後、配列judgeをスプレッドシートのC列に4行分書き出します。
関数Hisokaにこの2行を加えたのみです。

//スプレッドシートC列4行分に判定結果の入った配列judgeごと入力する。
  ss.getRange(1,3,N).setValues(judge);

ここまでのコードをまとめました。

//アクティブなスプレッドシートを選択するグローバル領域(共通の処理)
const ss=SpreadsheetApp.getActiveSheet();

//行数(人数)を取得する
const N=ss.getLastRow();


//【メンバー】がヒソカと同じ念系統か判定する関数
function Hisoka() {

  let array= [];
  let judge = [];

  //B列の各メンバーの念を配列arrayに格納
  array=ss.getRange(1,2,N).getValues();
  console.log(array);

  for(i=0;i<N;i++){
   
    //【メンバー】の念はヒソカと同じ「変化系」か?
    if(array[[i]]=='変化系'){
      judge.push(['ヒソカと一緒']); //キルアの場合
    }else{
      judge.push(['XXX']); //キルア以外
    }
  }
  console.log(judge);

  //スプレッドシートC列4行分に判定結果の入った配列judgeごと入力する。
  ss.getRange(1,3,N).setValues(judge);
}

//ヒソカチェックのクリア
function HisokaClear(){
  
  ss.getRange(1,3,N).clear();
}

お疲れ様でした。ブレイクタイムPhotoは、

横浜の夜景です。
思わずこの歌を歌いたくなりました。

←episode3               episode5→

←GAS自作サンプル集へ戻る

HUNTER×HUNTERのGAS自作サンプル集のページに戻る
初めてのGASに戻る


自己紹介

episode3 GAS【二次元配列は団地!!】範囲指定でまとめて入力「HUNTER×HUNTERで覚えるGoogle Apps Script」

この記事のシリーズを読むことで、アニメHUNTER×HUNTER(ハンターハンター)を通してGAS(Google Apps Script)の最初の一歩が学べます。

この記事では、

・配列は「0:ゴン」、「1:キルア」、「2:クラピカ」、「3:レオリオ」のイメージ

・配列を団地に例えて「キャラクター」と「念能力」の二次元配列を作成

・配列の長さをlengthを使って求め、同じ長さ分の行と列をスプレットシートに確保して配列を出力

についての概要を掴めます。

この記事で作成する配列は、キャラクター4人分の「キャラ名」と「念能力」を格納する4行2列の配列です。

シートに出力する関数、消去する関数の2つを作って、それぞれボタンに割り当て(登録)します。

また、シートに入力されている範囲をgetDataRangeで配列として扱えます。

まずは前回(episode2)の復習をします。

・セルA1に「ハンターハンター」と入力する関数と消去する関数を作り、それぞれをボタンに登録しました。

//アクティブなスプレッドシートを選択するグローバル(キャラ共通の処理)
const ss=SpreadsheetApp.getActiveSheet();


//入力とログ出力をする関数(ゴンさんの家)
function myInput() {
  
  //セル入力
  ss.getRange(1,1).setValue('ハンターハンター');

  //ログ出力
  console.log(ss.getRange(1,1).getValue());

}


//消去する関数(キルアさんの家)
function myClear() {

  //セルA1を消去
  ss.getRange(1,1).clear();

}

それでは、ここから配列にキャラクターの名前と念能力を格納していきます。

二次元配列に格納するするデータは、

「 「ゴン」 、「強化系」 、
「キルア」 、「変化系」 、
「クラピカ」 、「具現化系」 、
「レオリオ」 、「放出系」 」

です。

スプレッドシートはExcelの様に行と列の二次元ですので、二次元配列を使って入力します。

二次元配列や配列と聞くと難しそうですが、イメージは「団地(マンションでも)」です。

配列は添字0から始まります。

0階・・・ゴン(00号室に「ゴンの名前」 、01号室に「ゴンの強化系」)

1階・・・キルア(10号室に「キルアの名前」 、11号室に「キルアの変化系」)

2階・・・クラピカ(20号室に「クラピカの名前」 、21号室に「クラピカの具現化系」)

3階・・・レオリオ(30号室に「レオリオの名前」 、31号室に「レオリオの放出系」)

というイメージで二次元配列を「団地」と捉えると、掴みやすくなるのかも知れません。

以上を踏まえてコードを書いていきます。

まずは、キャラクターの名前と念の系統を入力する関数であるnenArray(配列は英語でarray)から解説します。

キャラクター名と念系統の二次元配列をこのように作成します。

//アクティブなスプレッドシートを選択するグローバル領域
const ss=SpreadsheetApp.getActiveSheet();

//スプレッドシートにキャラクターの名前と念系統の入った配列を出力する
function nenArray(){

  //二次元配列hhにキャラクターの名前と念系統を格納
  const hh = [
      ['ゴン','強化系'],
      ['キルア','変化系'],
      ['クラピカ','具現化系'],
      ['レオリオ','放出系']
    ];
  
  //配列hhをログに出力
  console.log(hh);
}

実行すると、配列がログに出力されました。

次に、上記の二次元配列は4行2列ですので、スプレッドシートのA1を起点に4行2列分のデータを確保するプログラムを書いていきます。

まず、行と列が4行2列になっていることをログ出力で確認します。
長さを調べるのにlengthを使います。

//アクティブなスプレッドシートを選択するグローバル領域
const ss=SpreadsheetApp.getActiveSheet();

//スプレッドシートにキャラクターの名前と念系統の入った配列を出力する
function nenArray(){

  //二次元配列hhにキャラクターの名前と念系統を格納
  const hh = [
      ['ゴン','強化系'],
      ['キルア','変化系'],
      ['クラピカ','具現化系'],
      ['レオリオ','放出系']
    ];
  
  //配列hhをログに出力
  console.log(hh);

  //行の長さを調べる
  console.log(hh.length);

  //列の長さを調べる
  console.log(hh[0].length);

}

行が4人分のhh.lengthが4になることはイメージしやすいと思います。

その下のhh[0].lengthですが、これは[‘ゴン’,’強化系’]の長さを調べていて、2列分なので2と返しています。


キルアのhh[1].lengthにしても同じ結果になりますが、全てのキャラクター(行)に対して2列になるので、代表してゴンのhh[0].lengthを用いております。

この行と列の長さは、スプレッドシートにキャラクターの配列hhを出力する時に、出力範囲を一致させる必要があるので調べました。

それではスプレッドシートに出力致します。
末尾にこの部分を追加します。

//二次元配列hhを格納するために、スプレッドシートの4行2列を確保して出力する
  ss.getRange(1,1,hh.length,hh[0].length).setValues(hh);

ここまでのコードの全てです。

//スプレッドシートにキャラクターの名前と念系統の入った配列を出力する
function nenArray(){

  //二次元配列hhにキャラクターの名前と念系統を格納
  const hh = [
      ['ゴン','強化系'],
      ['キルア','変化系'],
      ['クラピカ','具現化系'],
      ['レオリオ','放出系']
    ];
  
  //配列hhをログに出力
  console.log(hh);

  //行の長さを調べる
  console.log(hh.length);

  //列の長さを調べる
  console.log(hh[0].length);

  //二次元配列hhを格納するために、スプレッドシートの4行2列を確保して出力する
  ss.getRange(1,1,hh.length,hh[0].length).setValues(hh);

}

次に、データを消去に関するmyClear関数を作成します。
消去する範囲を、スプレットシート上のデータが存在する範囲として捉えることの出来るgetDataRangeを使っています。

シートオブジェクト.getDataRange()

以下、myClear関数のコードです。

//出力した配列を消去する
function myClear() {

  //出力した配列をgetDataRangeを使って取得して消去する
  ss.getDataRange().clear();

}

この書式でシート上のデータを配列として取得できました。
その下のclearメソッドで入力範囲を削除できます。

ここまでのコード全体を記述します。

//アクティブなスプレッドシートを選択するグローバル領域
const ss=SpreadsheetApp.getActiveSheet();


//スプレッドシートにキャラクターの名前と念系統の入った配列を出力する
function nenArray(){

  //二次元配列hhにキャラクターの名前と念系統を格納
  const hh = [
      ['ゴン','強化系'],
      ['キルア','変化系'],
      ['クラピカ','具現化系'],
      ['レオリオ','放出系']
    ];
  
  //配列hhをログに出力
  console.log(hh);

  //行の長さを調べる
  console.log(hh.length);

  //列の長さを調べる
  console.log(hh[0].length);

  //二次元配列hhを格納するために、スプレッドシートの4行2列を確保して出力する
  ss.getRange(1,1,hh.length,hh[0].length).setValues(hh);

}


//出力した配列を消去する
function myClear() {

  //出力した配列をgetDataRangeを使って取得して消去する
  ss.getDataRange().clear();

}

シートのボタンにそれぞれのスクリプトを割り当てて実行します。

ボタンを右クリックで選択して、右上の「・・・」から「入力」ボタンに「nenArray」、消去ボタンに「myClear」のスプリクトを割り当てます。

これで、キャラの名前と念の入った配列をボタンを押すことで手軽に実行出来る様になりました。


お疲れ様でした。ブレイクタイムPhotoは、

横浜のクルーズ船です。

ご精読有難うございました。

■ GASの入門書の紹介です ■

詳解! Google Apps Script完全入門 [第3版]
単行本
Kindle版(電子書籍)

←episode2               episode4→

←GAS自作サンプル集HUNTER×HUNTERへ戻る

HUNTER×HUNTERのGAS自作サンプル集のページに戻る
初めてのGASに戻る


自己紹介