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

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

新規登録して質問してみよう
ただいま回答率
85.48%
Google Apps Script

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

Q&A

解決済

2回答

1596閲覧

for構文の回数が一回多くなる

TD0

総合スコア22

Google Apps Script

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

0グッド

0クリップ

投稿2018/11/03 07:53

編集2018/11/03 10:22

お世話になります。
こちらのサイトを参考に、スプレッドシートに登録されている人にメールを一括送信するgasを組んでいます。
https://liapoc.com/bulk-transmission.html

実際に実行すると、メールは送信されますが、for 構文が最後の空の列を取得して終わります。
動作が一回分多いのですが、これをどう変更すればよろしいでしょうか?

よろしくお願いいたします。

gas

1function myFunction() { 2 3 4var mySheet = SpreadsheetApp.getActive().getSheetByName('連絡先'); 5var rowSheet = mySheet.getDataRange().getLastRow(); 6 7 8var docTest=DocumentApp.openById("/*documentID*/"); 9var strDoc=docTest.getBody().getText(); 10 11for(var i=2;i<=rowSheet;i++){ 12//for(var i=2;i<=rowSheet;i--){修正のご指摘をいただきました。 13 14var strEmail=mySheet.getRange(i,1).getValue();  15var strSei=mySheet.getRange(i,2).getValue(); 16var strMei=mySheet.getRange(i,3).getValue(); 17 18var strBody=strDoc.replace(/{姓}/g,strSei).replace(/{名}/g,strMei); 19 20 21/* メール表題、fromアドレス、差出人名を準備 */ 22var strSubject = strSei + " " + strMei+"様 ●●●●●●●●"; //姓 名 様 メールタイトル 23var strFrom="/*Mailadress*/"; //From 24var strSender="/*Name*/"; //差出人 25 26 27 /* メールを送信 */ 28 MailApp.sendEmail( 29 strEmail, //toアドレス 30 strSubject, //メールタイトル 31 strBody, //本文 32 { 33 from: strFrom, //fromアドレス 34 name: strSender //差出人 35 } 36 ); 37 38 } 39}

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

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

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

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

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

ikedas

2018/11/03 10:11

掲載しておられるのは、実際に実行したコードでしょうか? 相違がないかよく確認して、違っていれば訂正してくださいませんか。
TD0

2018/11/03 10:13

/* を除いて、全て実行した通りのコードをお載せしています。
ikedas

2018/11/03 10:17

forの行は本当にこうなっているんですか……?
TD0

2018/11/03 10:19

すみません、++で実行しています^^;
ikedas

2018/11/03 10:22 編集

質問本文を訂正してください。この追記・修正の依頼は隠れてしまうので、他の人が気づきません。
TD0

2018/11/03 10:30

ご指摘ありがとうございました。
guest

回答2

0

ベストアンサー

  • var rowSheet = mySheet.getDataRange().getLastRow();

ikedas様が回答で引用された仕様のとおりなので、冗長です。var rowShet = myShet.getLastRow();とすべきです。

  • ロジックにより、ループが1回多くなる理由(今回はあてはまらないように見えるので参考程度に)

手続型プログラミングでありがちなのは、forの終了条件の判定で、不等号でイコールを含むかどうかを誤っているパターン。これに対処するには、そもそもforをしない、という選択を考えるべきです。具体的にはArray.prototype.forEachを利用するなどをご検討ください。

  • 今回の1回多い理由と対処

ロジック上の誤りには見えないので、データ起因です。つまり回答は自分で探すしかないです。そこで探しかた。
どうやってループが1回多いと思ったかが疑問です。MailAppは、宛先が不正だとエラーになるので、仮にA列が空白だったら、メールは送信されないため(その後の実行も中断する)ので気付けないはず(例えばAからC列は5行しかデータがないのに、F6にタイプミスなどで文字があるときには、A6が空白なので、メール送信エラーで結局5通しか送信できない。あり得ないが送信できたとして、空白の宛先なので誰も知りようがない)。
仮に、メールのあてさきや姓、名が同じものが2通来たことを根拠に判定しているとしても、それは行が非表示になっているなどして見えないだけで、ループが1回多いかどうか分からないはず。
さらに、この2つの組み合わせとして、質問者様は3行と思っているのに、getLastRowは6を取得し、5行目のA列がないため、1回しか多くないようにみえてるパターンもあり得ます。
などと考えると、gasが取得しているrowSheetやそれぞれの都度のstrEmailなどをLogger.logして見ていくほか原因も対処法も不明です
(一般論として、strEmailなどが""だったらbreak/continueするというのは対処としてなくはないですが、メールが2通来ているパターンは対処できません)

  • A列の最終行を知りたい場合

A,B,Cはペアなのでこれだけでは上手くいきませんが、A列にあるデータの個数(スプレッドシート関数で言うCOUNTA(A:A))は、下記のように取得できます。ただし、こちらはCOUNTA相当なので、途中にA列にデータがない行があると、A列のデータがある最終行を取得できない(足りなくなる)ので、ご注意ください。

javascript

1function getLastRowOfA(sheet) { 2 return sheet.getRange("A:A").getValues().filter(String).length; //"A:C"とやっても動かないのでご注意ください 3}

投稿2018/11/03 11:48

papinianus

総合スコア12705

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

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

TD0

2018/11/03 15:06

他の条件式についても順次勉強に励みます… ループが多いと気づいたきっかけは実行トランスクリプトからです。記載されているメールアドレス全てに確実にメールは送信されているため、確認をしたところ最後のメール送信の後、もう一度アドレス・姓名が空の状態で送信を試みていました。メールは正しく、一行一件送信されています。 ご指摘の通りループが止まらない状態なのかもしれません。エラーが発生して強制的に終了しているだけなのかもしれないです… 元データには空白等はありません。A列の最終行取得のアイデアを拝借して再構築してみます。
papinianus

2018/11/04 23:41

フォームの回答だと考えにくいですが、空白がある、のではなく使用していない列(Z列とか)に余計なデータがあるのでは、というのが推測です。 確認方法としては Logger.log(mySheet.getDataRange().getValues())とすると取得した全データが見れるので思ったデータになっているか見てください
TD0

2018/11/05 01:59

ご指摘の通り、行末にデータが含まれていました。 (共同編集者がいたため、作成過程のメモを下欄に残していたようです。) 大変丁寧にご指導いただいて、ありがとうございました。 今後とも何卒よろしくおねがいいたします。
guest

0

SheetのGetDataRange()の説明によると

This is functionally equivalent to creating a Range bounded by A1 and (Range.getLastColumn(), Range.getLastRow()).

説明がちょっとわかりにくいですが、mySheet.GetDataRange()は、シートの左上から、データが入っている一番右・一番下までの範囲を返すようです。ですから最終行より下 (左から3つめまでのセルとは限らない) にデータや関数が入っていたりすれば、mySheet.GetDataRange().getLastRow()はその行番号を返します。つまりmySheet.getLastRow()と同じになるようです。

特定の列だけを調べてデータが入っている最後の行を返すようなメソッドはないようです (あるのかもしれませんが私は見つけられませんでした)。不要なデータのあるセルを消すか、またはセルが空であれば繰り返しをやめるようにしてはどうでしょうか。

投稿2018/11/03 10:55

編集2018/11/03 10:58
ikedas

総合スコア4333

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

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

TD0

2018/11/03 14:59

繰り返しをやめるという選択肢、検討してみます。 次のステップとしてonFormsubmitのトリガー設定と、 アドオンとしての公開を実践してみようとしていたため、 mySheet.GetDataRange().getLastRow()を設定していました。 (mySheet.getLast.Row()はご指摘の通り結果は同じだと把握しています。) 特定列に絞れないんですね…セルに関しては一定規則のもとフォームから転送されるデータですので空は存在しないものとして構築しています。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問