GASで「ねこあつめ」のメッセージを使って、配列に慣れていく「ねこあつめシリーズその14」

この記事では、GAS(Google Apps Script)で「ねこあつめ」をChatworkに送信する時に、配列の取り扱いに慣れて行くことが出来るプログラムの作成を目的としています。

お世話になった記事は、いつも隣にITのお仕事さんの

【初心者向けGAS】スプレッドシートのセル範囲の値を二次元配列として取得して取り扱う方法

です。

今回の内容に入る前に、前回とそれ以前の復習をします。
前回はChatworkを使う際、APIトークンを別領域に格納するのに、プロパティストアを使いました。
また、今までは、下記のようなスプレッドシートを使って、猫ちゃんの名前をChatworkに書き出して、1番右の列を「済」にしてきました。

前回のコードです。

//メインの関数でAmazonにDVDの注文をする
function myFunction() {
  const ss = SpreadsheetApp.getActiveSheet();
  let lastRow = ss.getLastRow();//最終行を取得
  const token=PropertiesService.getScriptProperties().getProperty('CW_TOKEN');//←ここを追加

  for (let i = 2; i <= lastRow; i++) {

    //もしもD列の「済」が空白だったらA列の「なまえ」を出力してD列を「済」にする
    if (!ss.getRange(i, 4).getValue()) {

      //AmazonがDVDの注文を受け取る
      const body=ss.getRange(i, 1).getValue();

      //ここでAmazonが宅配業者みたいなsendMessage関数にDVDの配達を依頼する
      sendMessage(token,body); //←ここに引数tokenを追加する
      ss.getRange(i, 4).setValue('済');

      //もしも最終行以上になったらセル範囲を消去する
      if (i >= lastRow) {
        ss.getRange(2, 4, lastRow - 1).clearContent();
      }
      break;
    }
  }
}

//宅配業者のようなsendMessage関数がAmazonからDVDを受け取って、配達を行う
function sendMessage(token,body){  //←ここの引数にtokenを加える
  const cw=ChatWorkClient.factory({token:token}); //←APIトークンの所をtokenに置き換える
  cw.sendMessageToMyChat(body);
}

今回の内容に入る前に、ねこあつめ画像で癒されます。

さて、今回の内容に入ります。

これまでA列の猫ちゃんの名前を送ってきましたが、B列の「しゅるい」とC列の「とくちょう」は何もしませんでした。
そこで今回はB列、C列も出力して行きます。

13行目のA列の猫ちゃんの名前を格納したbodyの所を変更して、B列やC列のデータも入れるようにします。
下記のコードの13行目から16行目までを追加変更しました。

//メインの関数でAmazonにDVDの注文をする
function myFunction() {
  const ss = SpreadsheetApp.getActiveSheet();
  let lastRow = ss.getLastRow();//最終行を取得
  const token=PropertiesService.getScriptProperties().getProperty('CW_TOKEN');//←ここを追加

  for (let i = 2; i <= lastRow; i++) {

    //もしもD列の「済」が空白だったらA列の「なまえ」を出力してD列を「済」にする
    if (!ss.getRange(i, 4).getValue()) {

      //AmazonがDVDの注文を受け取る
      let body="";  //←ここで、bodyにA列、B列、C列のデータを追加していくので、bodyをletで変数として宣言
      body+=ss.getRange(i,1).getValue()+'\n';
      body+=ss.getRange(i,2).getValue()+'\n';
      body+=ss.getRange(i,3).getValue()+'\n';
      
      //ここでAmazonが宅配業者みたいなsendMessage関数にDVDの配達を依頼する
      sendMessage(token,body);
      ss.getRange(i, 4).setValue('済');

      //もしも最終行以上になったらセル範囲を消去する
      if (i >= lastRow) {
        ss.getRange(2, 4, lastRow - 1).clearContent();
      }
      break;
    }
  }
}

//宅配業者のようなsendMessage関数がAmazonからDVDを受け取って、配達を行う
function sendMessage(token,body){
  const cw=ChatWorkClient.factory({token:token}); //←APIトークンの所をtokenに置き換える
  cw.sendMessageToMyChat(body);
}

このコードを実行することで、A列からC列まで出力されています。

猫ちゃんたちの名前とともに種類や特徴がわかりますね。

ただ、ループでA列、B列、C列のセルを一つ一つ計3回アクセスして取得して、それを4匹分取得すると3×4で12回のアクセスの手間がかかってしまうんです・・・。
なので、配列を使うと便利です。

今回はcatという配列を使います。
下記コードの11行目で配列catを使って、1行3列分一気に格納しますので、getValuesと最後に「s」がついて複数形になっています。

また、スプレッドシートは二次元配列で扱うので、14行目〜16行目のcat[0][0]がA列の「なまえ」、cat[0][1]がB列の「しゅるい」、cat[0][2]がC列の「とくちょう」になっています。

配列は0か始まるので、cat[0]はcatという配列の1行目という意味です。
ループの中でcatには次の猫ちゃんの名前が入るので、配列catの1行目に次々と猫ちゃんデータが格納されるイメージです。

//メインの関数でAmazonにDVDの注文をする
function myFunction() {
  const ss = SpreadsheetApp.getActiveSheet();
  let lastRow = ss.getLastRow();//最終行を取得
  const token=PropertiesService.getScriptProperties().getProperty('CW_TOKEN');//←ここを追加

  for (let i = 2; i <= lastRow; i++) {

    //もしもD列の「済」が空白だったらA列の「なまえ」を出力してD列を「済」にする
    if (!ss.getRange(i, 4).getValue()) {
      let cat=ss.getRange(i,1,1,3).getValues();//←配列catで一気に1行3列分のデータを取得する ※getValue[s]でsが付く

      //AmazonがDVDの注文を受け取る
      let body="";  //←ここで、bodyにA列、B列、C列のデータを追加していくので、bodyをletで変数として宣言
      body+=cat[0][0]+'\n';//A列:猫ちゃんの「なまえ」
      body+=cat[0][1]+'\n';//B列:猫ちゃんの「しゅるい」
      body+=cat[0][2]+'\n';//C列:猫ちゃんの「とくちょう」
      
      //ここでAmazonが宅配業者みたいなsendMessage関数にDVDの配達を依頼する
      sendMessage(token,body);
      ss.getRange(i, 4).setValue('済');

      //もしも最終行以上になったらセル範囲を消去する
      if (i >= lastRow) {
        ss.getRange(2, 4, lastRow - 1).clearContent();
      }
      break;
    }
  }
}

//宅配業者のようなsendMessage関数がAmazonからDVDを受け取って、配達を行う
function sendMessage(token,body){
  const cw=ChatWorkClient.factory({token:token}); //←APIトークンの所をtokenに置き換える
  cw.sendMessageToMyChat(body);
}

配列を使うことによって、各回3回分のアクセスを1回(11行目)に減らせました。
なので、今まで各回3×4=12回だったのが、配列catを用いることで、各回1×4=4回のスプレッドシートのアクセスに減らせました。

ご精読ありがとうございました。

■参考文献の紹介■
初めてGASを学ぶ方向け。
スプレッドシートの基本的な使い方からGASのベースとなるJavaScriptの基礎文法、GASでの初歩的なプログラミングを学べます。

GASに少し慣れて来たら、基礎固めとリファレンスとしてこの本を通してじっくり学べます。

サイトマップはこちらから

GASサンプル集に戻る
メインメニューに戻る
これからプログラミングを始める方へ
基本情報技術者へ
自己紹介

←前に戻るにゃん    次行くにゃん(=^x^=)→

paiza レベルアップ問題集 「STEP: 4 任意の数で何回割れる?」をPythonとGASで解いてみた

この記事を読むことで、PythonとGASで標準入力で被除数(割られる数N)・除数(割る数M)を取得し、whileループを使って、任意の数(M)で何回割ることが出来るのか回数を数える方法が学べます。

どちらのコードでも割り算の過程や変数の値の変化を追いやすい様に、トレースのコードを設けています。

ループの最初にIF文で割り切れない(余りが0ではない)場合はbreakでループを抜けるようにしています。

このコーナーでは、学習コンテンツpaizaラーニングレベルアップ問題集をPythonとGASの両方で解いて全コードの解説をしています。
PythonとGASの両方のコードを用いて、全コード及び部分的にも可能な限り詳細に記載いたしました。

GASはスプレッドシートを使っています。
GASはGoogle Apps Scriptと言って、JavaScriptの文法をベースにしているので、JavaScriptの学習中の方にもお役立て出来るかも知れません。

サイトマップはこちらから

paizaレベルアップ問題集でPythonとGASを解いて見たに戻る
メインメニューに戻る
Python自作サンプル
GASサンプル
基本情報技術者試験

paizaでの解答はPythonで行いましたが、この記事ではPythonのコードと共に、同じ問題を現在学習中のGASだったらどう解くのか、スプレッドシートでバインドして作ってみました。

任意の数で何回割れる? (paizaランク D 相当)

問題:
整数 N, M が与えられます。
N が何回 M で割れるかを求め、出力してください。

この記事では、下記の入力例3の場合にリストの個数N=81,M=3として81が3で何回で割れるかを求めます。

入力例3
81 3

出力例3
4

ではまず、Pythonで解いてみます。
今回は、paiza.ioを使って解きます。paiza.ioの使い方はこちらから。

■ Pythonでの解き方 ■

下準備として、paiza.ioにこの様に入力します。
(入力例1をそのままioにコピーしただけ。)

手順として、

1:数値N=81,M=3を取得する

2:割り算を実行する処理の回数をcountで求めるので、count変数を0で初期化する


3:ループの最初にNがMで割り切れない場合は、breakでループを抜けるよう設定しています。
whileループでNがM以上という条件を満たす間、ループを回します。
Mで割っていくのにNが2.999などの数ですと、割り切ることが出来ないからです。


4:ループの中で割り算を実行します。

5:countをインクリメントします。

6:countを表示します。

で、行います。

まずは、プログラムの各変数の動きを追いやすいように、トレースのio出力結果と、トレースのコードを添えます。

1回目の除算

2回目の除算

3回目の除算

4回目の除算

#被除数Nと除数Mを標準入力で取得
N,M=map(int,input().rstrip().split(' '))


#NをMで割れる回数を格納する変数countを初期化する
count=0


print('<<<ループに入る>>>')

#whileループでNがM以上で尚且つ割り切れる条件の時にループを回す
while N>=M:
    print('除算前のcount:【'+str(count)+'回】')
    print('除算前のN:'+str(N))
    if N%M!=0:
        break
    
    #除算実行
    print('---「'+str(N)+'÷'+str(M)+'」を実行---')
    N/=M
    
    #countのインクリメント
    count+=1
    
    print('除算後のcount:【'+str(count)+'回】')
    print('除算後のN:'+str(N))
	
    #ループの区切り
    print('-------------------')

print('<<<ループを抜けた>>>')

print(count)

このままでは、出力結果である出力例3に対して冗長なコードが含まれているので、解答以外のprint文をコメントアウトします。

#被除数Nと除数Mを標準入力で取得
N,M=map(int,input().rstrip().split(' '))


#NをMで割れる回数を格納する変数countを初期化する
count=0


#print('<<<ループに入る>>>')

#whileループでNがM以上で尚且つ割り切れる条件の時にループを回す
while N>=M:
    #print('除算前のcount:【'+str(count)+'回】')
    #print('除算前のN:'+str(N))
    if N%M!=0:
        break
    
    #除算実行
    #print('---「'+str(N)+'÷'+str(M)+'」を実行---')
    N/=M
    
    #countのインクリメント
    count+=1
    
    #print('除算後のcount:【'+str(count)+'回】')
    #print('除算後のN:'+str(N))

    #ループの区切り
    #print('-------------------')

#print('<<<ループを抜けた>>>')

print(count)

スッキリするように、コメントアウトした部分を省いたコードです。


#被除数Nと除数Mを標準入力で取得
N,M=map(int,input().rstrip().split(' '))


#NをMで割れる回数を格納する変数countを初期化する
count=0

#whileループでNがM以上で尚且つ割り切れる条件の時にループを回す
while N>=M:
    if N%M!=0:
        break
    
    #除算実行
    #print('---「'+str(N)+'÷'+str(M)+'」を実行---')
    N/=M
    
    #countのインクリメント
    count+=1
    
print(count)

ioの出力結果です。

■ GASでの解き方 ■

では、同じ問題をGASで解いてみます。
まず、スプレッドシートにこの様に配置しました。

スプレッドシートの黄色いセルの所に「Mで割り切れた回数」を出力します。
割り切れた回数は変数countに格納します。
また、countを二次元配列count2に追加して、スプレッドシートに出力します。

※スプレッドシートに表示する場合は、ループを使って一次元配列ではなく、二次元配列としてからの配列に追加をして作成します※

手順はこのようになります。

1:スプレッドシートからアクティブシートをアクセスする

2:スプレッドシートの緑色のセルから割られる数の被除数N(この例では「81」)を取得する


3:スプレッドシートの灰色のセルから割る数の除数M(この例では「3」)を取得する


4:割り切れた回数を格納する変数countを宣言して0で初期化する


5:whileループでNがM以上という条件を満たす時にループを回す。
また、IF文でNをMで割り切れない(N%Mが0では無い)場合にはループを抜ける。
除算を実行して、割り切れた回数のcountをインクリメントする。

6:スプレッドシートに出力する二次元配列配列count2を宣言する

7:countをcount2に二次元配列として追加する

8:スプレッドシート出力前に二次元配列count2のログ出力で確認する

9:スプレッドシートの黄色いセルに割り切れた回数が格納された二次元配列count2を出力する

手順1: スプレッドシートからアクティブシートをアクセスする

const ss=SpreadsheetApp.getActiveSheet();

ここで定数ssにSpreadsheetAppから階層を辿ってアクティブシートにアクセスしています。

手順2: スプレッドシートの緑色のセルから整数N(この例では「10」)を取得する

let N=ss.getRange(1,2).getValue();

※Nを割っていくので、Nの値が変わる、すなわち変数なので定数のconstではなく変数のletで宣言をします※

手順3:スプレッドシートの灰色のセルから割る数の除数M(この例では「3」)を取得する

const M = ss.getRange(2, 2).getValue();

手順4:割り切れた回数を格納する変数countを宣言して0で初期化する

let count=0;

手順5:
whileループでNがM以上という条件を満たす時にループを回す。
また、IF文で、NをMで割り切れない(N%Mが0では無い)時にループを抜ける。
除算を実行して、割り切れた回数のcountをインクリメントする。

1回目の除算

2回目の除算

3回目の除算

4回目の除算

whileループの部分のコードです。

/*
  whileループでNがM以上という条件を満たす時にループを回す。
  また、IF文でNをMで割り切れない(N%Mが0では無い)場合にはループを抜ける。
  除算を実行して、割り切れた回数のcountをインクリメントする。
  */

  console.log('<<<ループに入る>>>');

  while (N >= M) {
    if (N % M != 0) {
      break
    }

    console.log(`除算実行前のN:${N}`);
    console.log(`除算実行前のcount:【${count}回】`);

    //除算実行
    N /= M;

    //割り算の回数をインクリメント
    count++;

    console.log(`除算実行後のN:${N}`);
    console.log(`除算実行後のcount:【${count}回】`);

    //ループ区切り
    console.log('-----------------------');

  }

  console.log('<<<ループを抜けた>>>');

手順6:スプレッドシートに出力する二次元配列配列count2を宣言する

let count2=[];

手順7:countをcount2に二次元配列として追加する

count2.push([count]);

手順8:スプレッドシート出力前に二次元配列count2のログ出力で確認する

console.log(count2);

手順9:スプレッドシートの黄色いセルに掛け算の計算結果が格納された二次元配列count2を出力する

ss.getRange(4, 1).setValue(count2);

GASでの全コードはこちらになります。

function loop2no9() {

  //スプレッドシートからアクティブシートをアクセスする
  const ss = SpreadsheetApp.getActiveSheet();

  //スプレッドシートの緑色のセルから割られる数の被除数N(この例では「81」)を取得する
  let N = ss.getRange(1, 2).getValue();

  //スプレッドシートの灰色のセルから割る数の除数M(この例では「3」)を取得する
  const M = ss.getRange(2, 2).getValue();

  //割り切れた回数を格納する変数countを宣言して0で初期化する
  let count = 0;

  /*
  whileループでNがM以上という条件を満たす時にループを回す。
  また、IF文でNをMで割り切れない(N%Mが0では無い)場合にはループを抜ける。
  除算を実行して、割り切れた回数のcountをインクリメントする。
  */

  console.log('<<<ループに入る>>>');

  while (N >= M) {
    if (N % M != 0) {
      break
    }

    console.log(`除算実行前のN:${N}`);
    console.log(`除算実行前のcount:【${count}回】`);

    //除算実行
    N /= M;

    //割り算の回数をインクリメント
    count++;

    console.log(`除算実行後のN:${N}`);
    console.log(`除算実行後のcount:【${count}回】`);

    //ループ区切り
    console.log('-----------------------');

  }

  console.log('<<<ループを抜けた>>>');

  //スプレッドシートに出力する二次元配列配列count2を宣言する
  let count2 = [];

  //countをcount2に二次元配列として追加する
  count2.push([count]);

  //スプレッドシート出力前に二次元配列count2のログ出力で確認する
  console.log(count2);

  //スプレッドシートの黄色いセルに割り切れた回数が格納された二次元配列count2を出力する
  ss.getRange(4, 1).setValue(count2);

}

宜しかったらコピペしてアレンジして見て下さい。
お疲れ様でした、ブレイクタイムフォトはこちらになります。

よみうりランドのXmasイルミネーション、「ジュエルミネーション」から1枚、アテネの宮廷

■ 参考文献の紹介■

じっくり丁寧にPythonを学びたい方向け。
まずはpaizaラーニングなどの学習コンテンツで学んで、基礎をマスターしたら、この本でじっくりと初級から中級レベルを目指せます。

初めてGASを学ぶ方向け。
スプレッドシートの基本的な使い方からGASのベースとなるJavaScriptの基礎文法、GASでの初歩的なプログラミングを学べます。

GASに少し慣れて来たら、基礎固めとリファレンスとしてこの本でじっくり学べます。

サイトマップはこちらから

paizaレベルアップ問題集でPythonとGASを解いて見たに戻る
メインメニューに戻る
Python自作サンプル
GASサンプル
基本情報技術者試験

←前の問題へ          次の問題へ→