- Googleフォームの「配点・正解・解説」を取得
- getPoints
- isCorrectAnswer
- map関数 その2 戻り値設定
- filter関数で不要な要素を削除
- join()を使って配列を文字列に
- !==とは?
Google Apps Scriptを使ってGoogleフォームから項目を取り出し、フォームの構造をスプレッドシートに書き出すプログラムの作成ですが、フォーム作成に使われるパーツ(ラジオボタン・テキストボックスetc)ごとに違う要素について一つずつ確認して取り出す骨組みは出来てきました。
今回は、Googleフォームのなかでも管理・修正がめんどうな「配点・正解・解説」について取得したいと思います。
なぜめんどうなのかというと、これらはフォームの編集画面を開いただけでは設定・編集ができず、「解答集を作成」のボタンを押す必要があるからです。解説に至っては、一見しただけでは内容はおろか入力されているのかどうかも判別できません。
これらも、ほかの項目と一緒にシートに表記されると管理がラクになるはずです。
取得の方法を一つずつ考えていきましょう。
一番わかりやすいのは「配点」の項目取得です。
配点を設定できるItemは hasPoint = 1 となっているはずなので、その場合だけgetPoints() を使って点数を取得し、配列に追加します。
選択肢取得の前に入れていきます。
//配点取得処理開始 if (hasPoint == 1) { const itemPoint = testPartsItem.getPoints() ; itemSheetinput = itemSheetinput.concat(itemPoint); //アイテムタイプや質問内容の配列と合体 }
シートのタイトル行にも項目名「配点」を追記します。(24行目)
sheet.appendRow(['アイテムタイプ', '質問内容','配点']);
実行結果
配点可能なアイテムは「0」または配点が入力、配点設定できない項目(または、現時点で取得できない項目)は空白になっています。
正解の選択肢はどれかを取得
次は、「正解」を取得します。
執筆時点で取得できるのは、回答を「選択肢」として入力する「ラジオボタン・チェックボックス・プルダウン」の3つのみです。テキストボックス・グリッドアイテムなどは「正解」の情報を取得できません。また、時間入力タイプについてはフォーム上で正解を設定することができません(手動採点項目)
正解の情報は、選択肢である「choice」の中にテキスト情報と共に格納されており、isCorrectAnswer()で確認することができます。(正解であればTrue、正解ではなければfalse)
一番簡単な方法は、選択肢ごとに正解かどうかを入力するセルを追加する方法です。
選択肢1 | 正解? | 選択肢2 | 正解? | 選択肢3・・・ |
---|---|---|---|---|
選択肢1テキスト | false | 選択肢2テキスト | True | 選択肢3… |
ただ、これではシートが長くなってしまい、管理する際もわかりにくいです。できればこのように表記したいですよね。
正解 | 選択肢1 | 選択肢2 | 選択肢3・・・ |
---|---|---|---|
1,3 | 選択肢1テキスト | 選択肢2テキスト | 選択肢3… |
選択肢の前に正解を番号で表記、正解が複数設定されていればカンマで区切られると見やすくなります。
ということは、選択肢のテキストを取得した方法とは少し違うやり方になりそうです。
やり方はいくつか考えられます。素人の私が一番わかりやすいのは、「for」を使って選択肢を一つずつ確認し、isCorrectAnswer()がTrueだった選択肢の番号(配列のインデックス)を格納していく方法です。
ただ、せっかくテキストはmapを使って一気に取得したので、今回も配列に対する構文を使って一気に取得してみたいと思います。
今回の工程を日本語にするとこうです。
- 選択肢オブジェクトであるchoicesを使って、isCorrectAnswer()でその選択肢が正解かどうか調べる。
- もしも正解「True」だったらその選択肢の番号を取得(配列インデックス番号に1を足す)
- 正解選択肢の番号をまとめて配列で取得
- シート入力用の配列に追記(ただし、配列を文字列に変換する)
では一つずつスクリプトに変換します。
choicesの中から正解情報を抜き出すのは選択肢テキストと同様にmapで行えます。
const choicesCorrect = choices.map(x => x.isCorrectAnswer());
ただ、今回は最終的に[2,4]のように正解の番号の入った配列が欲しいので、mapを使って続けて配列を操作していきます。map関数は、要素のほかにインデックス番号を使って操作することができます。
functionの要領で、配列要素をxではなくelement、インデックス番号をindexとして上記を書き換えるとこのようになります。
const choicesCorrect = choices.map(function (element, index) { element = element.isCorrectAnswer(); //choicesをchoices.isCorrectAnswer(); に書き換え
この時点で、例えば正解の選択肢が2と3に設定されていたら、choicesの中身は
[false,true,true]
となります。
trueの部分をインデックス番号+1に置き換えましょう(番号はゼロから始まるため)
if (element === true) { element = index + 1; return element; } //正解設定されてたらインデックス番号+1に書き換え
これで、choicesの中身は
[undefined,2,3]
となりました。最後にfalseだった部分をカットします。配列を要素ごと削除するには、mapではなくfilterを使用する必要がある、とChatGPTが言っていたので、map関数を閉じて、filter関数を続けます。
}).filter(function (element) { return element !== undefined; }); //正解番号の要素だけ取得し直し
これで、choicesCorrectの中身は正解番号の配列になりました。
あとは、シート記入用に合体させます。
itemSheetinput = itemSheetinput.concat(choicesCorrect.join(), choicesText);
choicesCorrect.join()で、配列要素をまとめて一つの文字列要素「2,3」とすることができます。
タイトル行に項目名を追加して実行しましょう。
正解が1つの時には数値、複数の時には文字列なので、左寄せですが、正常に記入されました。
今回は選択肢取得の部分に追記しました。
//選択肢取得処理開始 if (hasChoice == 1) { const choices = testPartsItem.getChoices(); //選択肢を取得 const choicesText = choices.map(x => x.getValue()); //選択肢のテキストを取得 //正解に設定されている選択肢の番号をカンマ区切りで取得 const choicesCorrect = choices.map(function (element, index) { element = element.isCorrectAnswer(); //choicesをchoices.isCorrectAnswer(); に書き換え if (element === true) { element = index + 1; return element; }//正解設定されてたらインデックス番号+1に書き換え }).filter(function (element) { return element !== undefined; });//正解番号の要素だけ取得し直し console.log(choicesCorrect); itemSheetinput = itemSheetinput.concat(choicesCorrect.join(), choicesText); //アイテムタイプや質問内容の配列と合体 //正解番号は配列で格納されているのでjoinでカンマ区切り文字列に変換 }
長くなったので、解説の取得は次回にします。
コメント