GoogleApps

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

どうも、ぱやぱやです!!(@paya2_5routai)

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

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

この記事が最後です。



前回の記事はコチラ

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

前回は、いよいよコードの実装に入ったところでした。
(コードの中身だけ見たい方は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();    // 応募者リスト

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

ここまでのコードをまとめると、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配列のランダムなインデックス(添字)が入ります。

何故この書き方で、配列のインデックスをランダムに取得出来るのか…。
それはこの記事を読んでみて下さい!!

後は、これを当たりの人数分繰り返せば良さそうですね。
じゃあ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




-GoogleApps