質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Google スプレッドシート

Google スプレッドシートは、フリーで利用できる表計算ソフト。Webアプリのためインターネットに接続することで利用できます。チャートやグラフの作成のほか、シートを他のユーザーと共有したり、同時に作業を進めることも可能です。

Google Apps Script

Google Apps ScriptはGoogleの製品と第三者のサービスでタスクを自動化するためのJavaScriptのクラウドのスクリプト言語です。

Q&A

解決済

1回答

853閲覧

GAS 素人に知識とアイディアを下さい。

Banana

総合スコア3

Google スプレッドシート

Google スプレッドシートは、フリーで利用できる表計算ソフト。Webアプリのためインターネットに接続することで利用できます。チャートやグラフの作成のほか、シートを他のユーザーと共有したり、同時に作業を進めることも可能です。

Google Apps Script

Google Apps ScriptはGoogleの製品と第三者のサービスでタスクを自動化するためのJavaScriptのクラウドのスクリプト言語です。

0グッド

0クリップ

投稿2022/06/18 08:14

編集2022/06/19 04:49

前提

google formsから送信された回答内容(複数項目)をスプレッドシート内に掲示板のように1項目毎に分解し、日にち毎に並び替えて表示。
というスクリプト作成を行なっています。
現状、自分なりに出来上がったけど、本当にこれでよかったのか?FOR文とか多いし、同じ情報の定数を分岐用に重複作成しているし、もっと簡潔な書き方があるんじゃないかと思っているのですが、どうにもこうにも分からず、知識を分けていただけないかと投稿しました。

今件に関してスクリプトを二つ載せます。

1つ目は失敗作 [解決策分からずボツ]  //ひとつの変数[ formVal ]を元にで全文に対応できないかと書いてみたスクリプトです。
2つ目はの改善版です [動作確認済み]

1つ目に求める動作は以下です。

1.フォーマット回答受信 シート名”FORM” (内容はcolmA_タイムスタンプ、colmB-K_10個分の回答枠、colmL_増設した更新日枠)
2. 1を変数[ formVal ]としてシート全体を取得
3.フィルター[ formFil1 ]を通して、新しい受信記録だけを抽出([ formVal ]内の更新日の有無で判別。新規の回答には更新日は含まれておらず、このスクリプトの完了時に日付を入れる仕組みです。)
4.その後も[formFil2] > [formFil3]と掲示用 シート名”ORG”仕様に形状を変え完成したものをシート名”ORG”に貼り付け
5. 3で’使用した変数[ formFil1 ]を再宣言
6.[ formFil1 ]のか空白の更新日欄に更新日を追加してシート名”FORM”内で上書き

[ エラ-症状 ]

エラー症状としては、上記4の”ORG”に貼り付けまでは問題なく動くのですか、
5.で変数[ formFil1 ]を再宣言した時に[formFil2]の値が返ってきてしまうというものです。
>>>どうしてそうなってしまうのか?原因が知りたいです。


2つ目は [動作確認済み]

2つ目は1つ目が解決できなかったので、最初から変数を[ formVal ]だけでなく[formVal_F]と[formVal_O]を重複作成し動作までこぎついたスクリプトです。
var formVal = form_sh.getRange(col_A + "2:" + col_L + form_sh.getLastRow()).getValues();
const formVal_F = form_sh.getRange(col_A + "2:" + col_L + form_sh.getLastRow()).getValues();
const formVal_O = form_sh.getRange(col_A + "2:" + col_L + form_sh.getLastRow()).getValues();

>>>これに関して、本当にこういった書き方でも良いのか?壊れやすい書き方は1つ目と2つ目のどっちなのか?もっと簡略化した書き方やアドバイスをいただきたいです。

素人ながら考えたスクリプトですので悪しからず、、、
説明文が悪く、6/18に書き直しをしてみました。もしよろしければ、答え合わせに付き合っていただける方是非、返答をお願いします。
よろしくお願いします!!

該当のソースコード

GAS

1function RefreshUpdate() {  ///1つ目の失敗作 (ここの掲示用に書き直したので歪な文章の可能性あり) 2 3 //COL指定 4 const col_A = "A"; 5 const col_B = "B"; 6 const col_L = "L"; 7 8 //シート取得 9 var ss = SpreadsheetApp.getActiveSpreadsheet(); 10 const form_sh = ss.getSheetByName('フォームの回答 1'); 11 const org_sh = ss.getSheetByName('掲示板'); 12 13 //値変数取得 シート名”FORM” 14 var formVal = form_sh.getRange(col_A + "2:" + col_L + form_sh.getLastRow()).getValues(); 15 16 //フィルター#1 >>更新日”空白”を抽出 17 var formFil1 = formVal.filter(array => array[11] === ""); 18 19 //値変数取得 シート名”ORG” 20 const orgVal = org_sh.getRange(col_A + "1:" + col_B + org_sh.getLastRow()).getValues(); 21 22 //時間取得 23 const posTime = new Date(formVal[0][0]); posTime.setHours(0, 0, 0, 0); //const posTime_Format = Utilities.formatDate(posTime, 'HST', 'yyyy/MM/dd '); 24 const update = new Date(); update.setHours(0, 0, 0, 0); 25 const update_Format = Utilities.formatDate(update, 'HST', 'yyyy/MM/dd '); 26 27 //フィルター#2 >>投稿日の削除 28 for (var f = 0; f < formFil1.length; f++) { 29 formFil1[f].shift(); 30 } if (f.length < 1) return; 31 32 //フィルター#3 >>フラットにして”空白”の削除 33 const formFil2 = formFil1.flat(); 34 const formFil3 = formFil2.filter(val => val); 35 36 //更新日挿入 37 const orgVal_Temp = [] 38 orgVal_Temp.push([update_Format, formFil3[0]]) 39 for (var ff = 1; ff < formFil3.length; ff++) { 40 orgVal_Temp.push(["〃", formFil3[ff]]); 41 } if (ff.length < 1) return; 42 43 //ORGシートに貼り直し 44 orgVal.splice(1, 0, ...orgVal_Temp); 45 org_sh.getRange(1, 1, orgVal.length, orgVal[0].length).setValues(orgVal); 46 47 //ここから FORMシートに更新日追加して上書き 48 for (var fff = 0; fff < formFil1.length; fff++) { 49 formFil1[fff].pop();   //更新日の”空白”削除 50 formFil1[fff].push(update_Format);   //更新日の追加 51 var found = false; 52 for (var fv = 0; fv < formVal.length; fv++) { 53 if (formVal[fv][0].getTime() === formFil1[fff][0].getTime() && formVal[fv][1] === formFil1[fff][1]) { 54 formVal[fv] = formFil1[fff];   //内容の上書き 55 found = true; 56 break; 57 } 58 } 59 } 60 61 form_sh.getRange(col_A + "2:" + col_L + (formVal.length + 2 - 1)).setValues(formVal); 62 63 64}; 65 66************************************************** 67 68function RefreshUpdate() {  ///2つ目 [動作確認済み] 69 70 //COL指定 71 const col_A = "A"; 72 const col_B = "B"; 73 const col_L = "L"; 74 75 //シート取得 76 var ss = SpreadsheetApp.getActiveSpreadsheet(); 77 const form_sh = ss.getSheetByName('フォームの回答 1'); 78 const org_sh = ss.getSheetByName('掲示板'); 79 80 //値配列取得 ”FORM” 81 var formVal = form_sh.getRange(col_A + "2:" + col_L + form_sh.getLastRow()).getValues(); 82 const formVal_F = form_sh.getRange(col_A + "2:" + col_L + form_sh.getLastRow()).getValues(); 83 const formVal_O = form_sh.getRange(col_A + "2:" + col_L + form_sh.getLastRow()).getValues(); 84 85 //フィルター#1 >>更新日”空白”を抽出 86 const formFil_F = formVal_F.filter(array => array[11] === ""); 87 const formFil_O = formVal_O.filter(array => array[11] === ""); 88 89 //値変数取得 ”ORG” 90 const orgVal = org_sh.getRange(col_A + "1:" + col_B + org_sh.getLastRow()).getValues(); 91 92 //時間取得 93 const posTime = new Date(formVal[0][0]); posTime.setHours(0, 0, 0, 0); 94 const posTime_Format = Utilities.formatDate(posTime, 'HST', 'yyyy/MM/dd '); 95 const posGetTime = posTime.getTime(); 96 const update = new Date(); update.setHours(0, 0, 0, 0); 97 const update_Format = Utilities.formatDate(update, 'HST', 'yyyy/MM/dd '); 98 const updateGetTime = update.getTime(); 99 100 //フィルター#2 >>投稿日の削除 101 for (var f = 0; f < formFil_O.length; f++) { 102 formFil_O[f].shift(); 103 } if (f.length < 1) return; 104 105 //フィルター#3 >>フラットにして”空白”の削除 106 const formVFlat_O = formFil_O.flat(); 107 const formFil2_O = formVFlat_O.filter(val => val); 108 109 //更新日挿入 110 const orgVal_Temp = [] 111 orgVal_Temp.push([update_Format, formFil2_O[0]]) 112 for (var ff = 1; ff < formFil2_O.length; ff++) { 113 orgVal_Temp.push(["〃", formFil2_O[ff]]); 114 } if (ff.length < 1) return; 115 116 //新しい日付を一番先頭に挿入 >>ORGシートに貼り直し 117 orgVal.splice(1, 0, ...orgVal_Temp); 118 org_sh.getRange(1, 1, orgVal.length, orgVal[0].length).setValues(orgVal); 119 120 //ここから FORMシートに更新日追加して上書き 121 for (var fff = 0; fff < formFil_F.length; fff++) { 122 formFil_F[fff].pop();   //更新日の”空白”削除 123 formFil_F[fff].push(update_Format);   //更新日の追加 124 var found = false; 125 for (var fv = 0; fv < formVal.length; fv++) { 126 if (formVal[fv][0].getTime() === formFil_F[fff][0].getTime() && formVal[fv][1] === formFil_F[fff][1]) { 127 formVal[fv] = formFil_F[fff];   //内容の上書き 128 found = true; 129 break; 130 } 131 } 132 } 133 134 form_sh.getRange(col_A + "2:" + col_L + (formVal.length + 2 - 1)).setValues(formVal); 135 136 137}; 138 139

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2022/06/18 11:39 編集

1番目の //フィルター#1 >>更新日”空白”を抽出 var formFil_F = formVal_F.filter(array => array[11] === ""); この右側の「formVal_F」はこの行以前のどこにも現れていないように見えます。 したがって正しくは「formVal」ではないですか? 「(これは1つ目のFOR文の後から、定数の中身が手前で走査した別の値が代入されてしまうという状態になり本来欲しい値が得られないので諦めました。)」 →「定数」とは、変数名でいうとどれですか? 「手前で操作した別の値」とは具体的にコードの部分の値ですか? 「本来欲しい値」とは、たとえば具体的にどのような値でしょうか?
Banana

2022/06/19 16:55

投稿内容が雑で申し訳ありませんでした。 昨日、投稿内容の書き直しをしましたので、もしよろしければもう一度ご確認をいただけないでしょうか? ぜひよろしくお願いいたします。
guest

回答1

0

ベストアンサー

1つめだけ回答します。

5.で変数[ formFil1 ]を再宣言した時に[formFil2]の値が返ってきてしまうというものです。
>>>どうしてそうなってしまうのか?原因が知りたいです。

まず、formFil1 は再宣言などされていません。formFil2 の値が返ってきてしまう、というのもちょっと意味が分かりません。

おそらく下記のようなことを聞きたかったのだろうと推測します。

「53行目で、for文の中で formVal を再利用しているが、この部分でformVal の中身をみると、各行1列目からタイムスタンプが削除されてしまっている 。なぜか?」


説明

1番目のコードの13行目~17行目

js

1 //値変数取得 シート名”FORM” 2 var formVal = form_sh.getRange(col_A + "2:" + col_L + form_sh.getLastRow()).getValues(); 3 4 //フィルター#1 >>更新日”空白”を抽出 5 var formFil1 = formVal.filter(array => array[11] === ""); 6

ここで、formVal は 各行のデータを要素に持つ2次元配列です。配列が入れ子になっています。
たとえば、フォームの回答を集約しているシートが下記のようになっていると仮定します。

イメージ説明

14行目直後 のformVal の内容は下記のようになるでしょう。

console.log(formVal); [ ["2022-05-14T11:00:00.000Z","回答A-1","回答B-1","回答C-1","回答D-1","回答E-1","","","","","",""], ["2022-05-20T12:00:00.000Z","回答A-2","回答B-2","回答C-2","回答D-2","回答E-2","","","","","","2022-06-20T01:00:00.000Z"], ["2022-07-08T01:00:00.000Z","回答A-3","回答B-3","回答C-3","回答D-3","回答E-3","","","","","",""] ]

 
17行目にあるように、formFil1は、formVal からfilter 関数で条件に合致する行(L列が空白)だけ抜き出した新しい配列です。

17行目直後の formFil1 の内容は下記のようになるでしょう。

console.log(formFil1); [ ["2022-05-14T11:00:00.000Z","回答A-1","回答B-1","回答C-1","回答D-1","回答E-1","","","","","",""], ["2022-07-08T01:00:00.000Z","回答A-3","回答B-3","回答C-3","回答D-3","回答E-3","","","","","",""] ]

 
ただし新しい配列と言っても、いわゆる浅いコピーと同じなので、formFil1 と formVal が1次元目で要素として保持しているのは、同じ配列オブジェクトへの参照です。

つまり、両者は各行に該当する配列オブジェクトを共有していることになります。

そして、24行目~27行目:

js

1 //フィルター#2 >>投稿日の削除 2 for (var f = 0; f < formFil1.length; f++) { 3 formFil1[f].shift(); 4 } if (f.length < 1) return; 5

ここで、shift 関数により、formFil1 の (0オリジンで) f 番目の1列目を削除しています。
上述の通り、formVal は formFil1 と同じ行(配列オブジェクト)への参照を要素として持ったままです。
この状態で、formFil1 経由で行に対して編集を行い、その後formVal 経由で行(配列オブジェクト)を読み込んだ場合、得られるデータはformFil1 での編集が反映された後のものになります。
なぜなら、同じオブジェクトを参照しているからです。

注意:下図の「参照@」というのは、説明のためのものであって、GAS の実装と必ずしも一致するとは限りません。

イメージ説明

投稿2022/06/20 12:10

編集2022/06/22 14:28
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Banana

2022/06/22 06:47

qnoirさん いつもすごく丁寧な説明と回答をありがとうございます。 同じオブジェクトの参照とは思いませんでした。 てっきり、それぞれの変数は新しい名前の変数(formFil1 >> formFil2)になった時点で単独の変数となっており、その前も後も干渉しないと思っていました。 やはり、こうなる場合には二つ目のスクリプトのように同じ中身の変数(var formVal , formVal_F , formVal_O)だとしても、その後の条件などによっては事前に変数を作っておいた方が良いのでしょうか?
退会済みユーザー

退会済みユーザー

2022/06/22 14:30 編集

>その後の条件などによっては事前に変数を作っておいた方が良いのでしょうか? → 今回の質問文にあるコードのように、あえて ・後からshift等を使って配列の中にある配列の要素を編集しており かつ ・その編集結果を互いに影響させたくない というならば、getValuesの時点から別々に取得した方がよいでしょう。 (つまり、getValuesを2回以上行い、2つ以上の変数に2次元配列を別々に格納するということです。これは2番目のコードで行っていることです)   getValuesによる取得処理をどうしても1回にとどめておきたいならば、破壊的メソッドである shift を使うのではなく、各行に対して slice を使う方法もあると思います。 具体的には、27行目~30行目を下記のように直すことで、formValに影響を及ぼすことなく、先頭の列を削除したデータがformFil1に格納されます。(※1) ``` //フィルター#2 >>投稿日の削除 for (var f = 0; f < formFil1.length; f++) { formFil1[f] =formFil1[f].slice(1); // slice は 元の配列に影響を及ぼさず、新しい配列を返す } ``` ただ1番目のコードは、この部分を直したところで正しく動作しないと思います。 というのは、28行目の時点でformFil1は先頭列を削除したデータになっているにもかかわらず、54行目では、先頭列が削除されていない前提で getTime() を実行しようとしているからです。 実際には先頭列のデータは削除されており、フォーム回収シートの2列目に該当するデータに対してgetTime()を実行することになってしまうので、期待する動作にならないはずです。 ※1:この言い方は厳密には語弊がありますが、いわんとすることはわかっていただけると思います。
Banana

2022/06/22 18:04

qnoirさん お返事ありがとうございます。 このスクリプトの作成には、スクリプトの動作中にも新しいフォームの回答が送られてくるであろうという懸念と、フォームの回答シート[form_sh]は自動生成されており、自動更新されていくものなので構成を変えて動作不良が起きないようにという2つの観点からの作成でした。 いずれにしろ、今回の問題点が解決できてよかったです!! ありがとうございます!!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問