プロが書く美しいコードじゃない、素人の稚拙なコードだからこそ、得られるものだってきっとある…そんな思いでコードを公開しています。どうぞ生暖かく見守ってください。

選択肢のテキストを取得する~配列の処理についてちょっとフカボリ

[tool1]フォームをシートに書き出しGoogle Apps Script
  • 配列の処理~繰り返しを使わず一気に変換
  • map関数
  • getValue

前回のおさらい

前回は、「もしもItemが選択肢を持つタイプだったら、選択肢を取得して一つずつ拾っていこう」ということで、getChoices()を使用して中身を確認しました。すると、

というように、選択肢もItem同様にいろいろな情報を含んだ一つの塊(オブジェクト)になっているようです。

ということは、Itemと同様に一つずつforで選択肢のテキストを拾って、、、となりそう?

Item配列を一列ずつ拾うなかでさらにChoiceを拾うループを回すのは、目が回りそう。いや、実際にやるのは機械の方なので大丈夫なんです。実際最初にコードを書いたときにはそうしていたんですが、調べていくうちにもう少し効率的な方法があることがわかりました。

一歩進んで別の方法を使ってみます。

配列の処理について ー mapを使う

Choicesはすでに[Choice,Choice]という配列になっていました。このような形式を「配列」というのですが、Google Apps Scriptの元であるJavaScriptでは配列に対してまとめて様々な処理することが可能なのです。

つまり、

  1. 配列の長さ分だけ繰り返しを作成
  2. 配列の最初のデータ(Choice)を取り出し
  3. getTitle()でテキストを取り出し
  4. その他必要要素を取り出し
  5. 配列の次のデータへ

というような一連の処理を、forを使わずスッキリと書くことができるのです。

配列の中身にいっぺんに一連の処理を行うには、「map」を使います。

例えばこんな感じ。

      testPartsItem = itemparts.asMultipleChoiceItem();
      const choices = testPartsItem.getChoices(); //選択肢を取得
      Logger.log(choices); //ログを確認

      const choicesText = choices.map(x => x.getValue());
      Logger.log(choicesText); //ログを確認

下二行が追加部分です。実行すると

これをsheetに入力すればよいのですが、前回取得した質問内容やアイテムタイプと合体させて、一つの配列にしてから、一行まとめてシートに書き込むように少し変更します。

シートへの入力を一行まとめて行うために、配列を作成

    // sheet.appendRow([itemType, itemText]); // それぞれシートの新しい行に入力
    let itemSheetinput=[itemType, itemText]; // ↑入力ではなく一旦配列に格納
    // Logger.log(itemSheetinput); //ログを確認

さらに、これをシートに入力していたアイテムタイプや質問内容の配列に合体させて、一行をいっぺんに入力すると少しスッキリしそうです。

これらをまとめて修正したコードがこちら

function myFunction() {

  // フォームを開く
  const form = FormApp.openByUrl(フォームのURL);
  // URLは'https://docs.google.com/fo******/edit'のように''で囲んで入力

  //フォームの要素を配列で取得
  const items = form.getItems();

  //スプレッドシートを開く。
  const spsheet = SpreadsheetApp.openByUrl(シートのURL);
  // URLは'https://docs.google.com/fo******/edit'のように''で囲んで入力
  const sheet = spsheet.getActiveSheet();
  //処理を加えるシートとして、ファイルを開いて最初に表示される(アクティブな)シートを設定

  sheet.clear(); //シートの内容をクリア

  //シートに行を追加し、formタイトル入力
  sheet.appendRow(['フォームタイトル', form.getTitle()]);
  // 項目タイトル行を作成
  sheet.appendRow(['アイテムタイプ', '質問内容']);

  for (let i = 0; i < items.length; i++) { //Item数をiと置き換えて、iを0から順番に項目の数だけ1ずつ増やす const itemparts = items[i]; //itemという配列のi番目の要素をitempartsとして取り出す。 const itemType = itemparts.getType(); //取得したitempartsのタイプを確認してitemTypeに保管 const itemText = itemparts.getTitle();//取得したitempartsの質問内容を確認してitemTextに保管 // sheet.appendRow([itemType, itemText]); // それぞれシートの新しい行に入力 let itemSheetinput = [itemType, itemText]; // ↑入力ではなく一旦配列に格納 if (itemType == 'MULTIPLE_CHOICE') { testPartsItem = itemparts.asMultipleChoiceItem(); const choices = testPartsItem.getChoices(); //選択肢を取得 const choicesText = choices.map(x => x.getValue()); //選択肢のテキストを取得
      itemSheetinput = itemSheetinput.concat(choicesText); //アイテムタイプや質問内容の配列と合体
      Logger.log(itemSheetinput); //ログを確認

    }
    sheet.appendRow(itemSheetinput); // 一項目まとめてシートの新しい行に入力
  }

}
元のフォーム

書き込まれたシート

ちなみに、最後のsheet.appendRow(itemSheetinput);をifのカッコ内(もし選択肢があれば…)に入れてしまうと、テキストボックスタイプなど選択肢がなかった場合にはシートに書き込みすらされないのでご注意ください。

私は一度やりました 笑

まとめ

勘が良いかたはお気づきかもしれません。

配列にmap処理が使えるならそもそもItemsもforを使わなくてもいいんでは…?

まさにその通りで、配列についてしっかり勉強すればもっともっとシンプルなコードを書くことができるハズです。

ここでは、素人が自分で考えてコードを書いて実行させることができた!という成功体験を重視していきたいと思いますので、プロから見ると冗長なコードかとは思いますが「とりあえず動く」コードを提示していきたいと思います。

処理するデータが大量になるにつれて、機械側の負荷が増える、処理に時間がかかってしまうなどの問題が出てきますので、あくまで個人利用範囲のデータで学習を進めてください。

コメント

タイトルとURLをコピーしました