Googleフォーム と Googleスプレッドシートを使ったTwitter抽選ツールの作り方【Part.6 抽選機能の実装2】

GoogleApps

『Googleフォーム と Googleスプレッドシートを使ったTwitter抽選ツールの作り方』の【Part.6】です。
※この抽選ツールの作成には、googleアカウントが必要になります

Part.6は、このツールの核となる
抽選機能のコード部分を書いていきます。

この記事が最後です。
もう少しです。頑張りましょう!

前回の記事はコチラ

目次

スポンサードリンク

前回は、いよいよコードの実装に入ったところでした。
(コードの中身だけ見たい方は6.コードまとめ+αに飛んで下さい)

1.事前準備

まずは、前回動作確認用に書いたコードは削除しましょう。

またはコードの先頭に「//」をつけて、コメントにしても良いでしょう。

//Browser.msgBox("Hello World");

2.処理の流れを先に考える

すぐにコードを書き始めるのではなく、先に処理の流れを整理しておきましょう。
書きながら考えれる人もいると思うんですが、最初のうちは先に大まかでも処理の流れを考えて書き始めると、戻り(修正)が少なくなると私は思います。

で、今回の機能は、
応募した人の中から、指定した人数をランダムで抽選する
を実装したいので、

(1)応募した人の一覧を取得する
(2)応募した人の一覧から、(ランダムな値を使って)指定された人数分の当選者を抽出する
(3)結果表示

この辺が必要になってきそうですね。
以下の説明もこの単位で行っていきます。

3.実装―応募した人の一覧を取得する

では実装に入ります。
※ここで出てくるコードは、すべて前回作った「myFunction」のカッコ内に書いてください。

まずは応募した人の一覧を取得します。
スプレッドシートのセルの値を取得するには、以下のように書きます。

var sheet = SpreadsheetApp.getActiveSpreadsheet();
var sheetList = sheet.getSheetByName('フォームの回答 1');

1行目で、今回の抽選用スプレッドシート全体を取得し、
2行目では、その中から「フォームの回答 1」という名前のシートを取得します。

次にセルから値を取得したいのですが、、

何行目から何行目を指定すれば良いでしょうか?

開始(From)は、「フォームの回答 1」を見てもらえばわかる通り、2行目から回答追加されていってるので「2」ですよね。
では終了(To)は・・?

正解はnで、応募数によって変わります。
なので、抽選する際にどこまでデータが入っているかを判断しないといけないのです。

「地道に2行目から数えていって、空白セルが出てきたら終了」でもいいんですが、今回は「getLastRow」を使います。
getLastRowは、シートの中のデータが入っている最終行を返すメソッドです。

var lastRow = sheetList.getLastRow();    // 応募者の最終行

この最終行を使って、応募者のリストを配列で取得します。

var lastRow = sheetList.getLastRow();    // 応募者の最終行
var aptList = sheetList.getRange(2, 2, lastRow - 1, 1).getValues();    // 応募者リスト

これで応募した人の一覧を取得することが出来ました。

※ここでは「フォームの回答 1」シートのB列のデータを取得しています。
この例でいうとTwitterIDにあたる部分ですね。
もしこれをC列とかD列にしたい場合は、
sheetList.getRange(2, 2, lastRow - 1, 1)
この部分の左から2番目の数値を変更します。Cなら3、Dなら4で、左から数えて何番目かをセットします。

ここまでのコードをまとめると、myFunction()はこのようになっています。

var sheet = SpreadsheetApp.getActiveSpreadsheet();
var sheetList = sheet.getSheetByName('フォームの回答 1');
var lastRow = sheetList.getLastRow();    // 応募者の最終行
var aptList = sheetList.getRange(2, 2, lastRow - 1, 1).getValues();    // 応募者リスト

4.実装―応募した人の一覧から、ランダムな値を使って指定された人数分の当選者を抽出する

次はランダムに当選者を抽出します。
ランダムというのがポイントですね。

このように書きます。

// ランダムで1件取得
var hitIdx = Math.floor( Math.random() * aptList.length );

これで、hitIdxに、aptList配列のランダムなインデックス(添字)が入ります。

何故この書き方で、配列のインデックスをランダムに取得出来るのか…。
それは、タカハシノリアキさんのコチラの記事を読んでみて下さい。
Google Apps Scriptで乱数を使っておみくじプログラムを作る

私はこのタカハシノリアキさんが著者のGoogle Apps Scriptの書籍で学習して、このツールを作成しました。
詳解! GoogleAppsScript完全入門 ~GoogleApps & G Suiteの最新プログラミングガイド~

乱数についてもう少し補足した記事です。
よければこちらも見てみてください。

後は、これを当たりの人数分繰り返せば良さそうですね。
繰り返しなので、じゃあforで回せば・・・

といきたいところですが、人数分回すだけだとある問題を解決できません。

それは『当たりの重複』です。
ランダムで同じ値が返ってくることもあるので、同じ人が抽出された場合は再抽選しないといけません。

なのでこのような形にでいきます。

var sheetLots = sheet.getSheetByName('抽選');
var winCnt = sheetLots.getRange("E2").getValue();  //①
var hitCnt = 0;
var winList = new Array();  //②

// 抽選
while (hitCnt + 1 <= winCnt) {
  // ランダムで1件取得
  var hitIdx = Math.floor( Math.random() * aptList.length );
  
  // 既に当選した人でないかチェック
  if (winList.indexOf(String(aptList[hitIdx])) == -1) {  //③
    winList.push(String(aptList[hitIdx]));  //④
    hitCnt++;  //⑤
  }
}

各処理の概要
①:抽選シートから当選人数を取得して、winCntに代入
②:当選者を保存する配列を定義
③:今回抽出された人が、既に当選していないか配列をチェック
④:当選者リストに追加
⑤:当選人数をカウント

当選者の数だけ抽選を回すのではなく、
重複の無い当たりが当選者数分出るまで回す
という処理になっています。

これで応募した人の一覧から、ランダムな値を使って指定された人数分の当選者を抽出することができました。
当選者はwinListに保持されています。

ここまでのコードをまとめると、このようになります。

var sheet = SpreadsheetApp.getActiveSpreadsheet();
var sheetLots = sheet.getSheetByName('抽選');
var winCnt = sheetLots.getRange("E2").getValue();
var sheetList = sheet.getSheetByName('フォームの回答 1');
var lastRow = sheetList.getLastRow();    // 応募者の最終行
var aptList = sheetList.getRange(2, 2, lastRow - 1, 1).getValues();    // 応募者リスト
var winList = new Array();
var hitCnt = 0;

// 抽選
while (hitCnt + 1 <= winCnt) {
  // ランダムで1件取得
  var hitIdx = Math.floor( Math.random() * aptList.length );
  
  // 既に当選した人でないかチェック
  if (winList.indexOf(String(aptList[hitIdx])) == -1) {
    winList.push(String(aptList[hitIdx]));
    hitCnt++;
  }
}

5.実装―結果表示

最後に結果表示です。
当選者がwinListに入ってますので、これをシートに展開すればOKです。

結果表示前には、結果表示領域のクリア処理もしておきます。

// 結果領域クリア
sheetLots.getRange(3, 2, sheetLots.getLastRow(), 1).clear();

// 抽選結果をセット
for(i = 0; i <= winList.length - 1; i++) {
  sheetLots.getRange(3 + i, 2).setValue(winList[i]);
}

winListの件数分をforループで回しながら、結果をシートに展開しています。

これで必要なコードが揃いました。

6.コードまとめ+α

最後に、今回書いたmyFunctionのコードのまとめです。
「// +α」と書いた部分は、あっても無くても抽選機能は動くのでどちらでも構いません。

function myFunction() {
  var sheet = SpreadsheetApp.getActiveSpreadsheet();
  var sheetLots = sheet.getSheetByName('抽選');
  var winCnt = sheetLots.getRange("E2").getValue();
  var sheetList = sheet.getSheetByName('フォームの回答 1');
  var lastRow = sheetList.getLastRow();    // 応募者の最終行
  var aptList = sheetList.getRange(2, 2, lastRow - 1, 1).getValues();    // 応募者リスト
  var winList = new Array();
  var hitCnt = 0;

  // +α
  // 確認メッセージ  
  var select = Browser.msgBox("当選人数" + winCnt + '人で抽選します。', Browser.Buttons.OK_CANCEL);
  if (select == 'cancel')
    return;  
  // +α

  // 抽選
  while (hitCnt + 1 <= winCnt) {
    // ランダムで1件取得
    var hitIdx = Math.floor( Math.random() * aptList.length );
    
    // 既に当選した人でないかチェック
    if (winList.indexOf(String(aptList[hitIdx])) == -1) {
      winList.push(String(aptList[hitIdx]));
      hitCnt++;
    }
  }
  
  // 抽選結果をセット
  for(i = 0; i <= winList.length - 1; i++) {
    sheetLots.getRange(3 + i, 2).setValue(winList[i]);
  }
}

ここまで済んだら保存して、スプレッドシートの抽選シートから、「抽選」ボタンを押してみましょう。

当選者ラベル(B3)の下に、応募した人の名前が表示されればOK。完成です!!

7.おわりに

この作ったツールを実際に使ってもらうには、
googleフォームのページから[送信]というボタンを押して、メールで送ったりクリップボードにコピーして共有します。

以上、『Googleフォーム と Googleスプレッドシートを使ったTwitter抽選ツールの作り方』連載終了、完結です!!

Part.6の公開が遅くなってすいませんでした m(. . )m

参考書籍

この抽選ツールを作るのにコチラの書籍で学習しました。

GoogleAppsScript(GAS)を使うことで、様々なGoogleサービスを自動化し、そして連携をすることができるようになります。スプレッドシートで表や帳票を作る…

高橋宣成さんという有名なブロガーの方の書籍です。高橋さんのブログはコチラ
いつも隣にITのお仕事

スポンサードリンク

ITリテラシー・プログラミングのまとめ記事