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

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

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

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

Google カレンダー

Google カレンダーは、Google社が提供する無料のスケジュール管理ツールです。パソコンやスマートフォン、タブレットなどからアクセスし、スケジュールの追加・変更が可能。Googleアカウントがあれば誰でも使用できます。

Google Apps Script

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

配列

配列は、各データの要素(値または変数)が連続的に並べられたデータ構造です。各配列は添え字(INDEX)で識別されています。

Q&A

解決済

1回答

2207閲覧

【GAS】 スプレッドシートのデータを配列で取得する方法

donguriko

総合スコア30

Google スプレッドシート

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

Google カレンダー

Google カレンダーは、Google社が提供する無料のスケジュール管理ツールです。パソコンやスマートフォン、タブレットなどからアクセスし、スケジュールの追加・変更が可能。Googleアカウントがあれば誰でも使用できます。

Google Apps Script

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

配列

配列は、各データの要素(値または変数)が連続的に並べられたデータ構造です。各配列は添え字(INDEX)で識別されています。

0グッド

2クリップ

投稿2021/12/12 10:20

編集2021/12/13 14:25

前提・実現したいこと

スプレッドシート「カレンダー転記用」シートの内容を配列データとして取得。
取得したデータを元にGoogleカレンダーに終日予定として登録がしたいです。
createAllDayEvent(予定件名,日付)で登録予定。

取得するデータは以下5種と
a)日付データ:B列 配列
b)拠点1予定:D列データ 
c)拠点2予定:E列データ
d)拠点3予定:F列データ
e)拠点4予定:G列データ

createAllDayEventの処理対象とするか否かの判定用として、(continueでスキップのつもり)
すでに予定登録済か否かのフラグ4種
f) b)の登録済フラグ:H列
g) c)の登録済フラグ:I列
h) d)の登録済フラグ:J列
i) d)の登録済フラグ:K列
それぞれを別個の配列としてデータ取得の想定。

<スプレッドシートイメージ>
!イメージ説明

配列データの取得がうまくできていないようで下のエラーが立ちます。
ネットや本を見たのですが、どこがマズイのか、どう直せばよいのかが分かりません。
(例)
・配列の指定に誤りがありますか?
・myDate配列に入れるデータを targetDateで指定しているする部分が違う??
>>そもそも、こんな指定は不要??
・行、列Indexの指定後に、getValuesで値取得して、各配列に投入する処理の記述が必要??
・配列でデータが取得できているかの確認のconsole.logの指定が違う???

★前回質問で配列についてレクチャーいただき、ちょっとだけ理解したつもり
でしたが、残念ながらまだ理解がふやふやのようです
があやふやのようです。。。 (https://teratail.com/questions/361425 の次の工程)

発生している問題・エラーメッセージ

<エラー>
Exception: Invalid argument: title
createEvent @ <処理2-1>転記シート→カレンダー登録.gs:76

該当のソースコード

以下、全文記載します。

function createEvent() {

//▼予定を追記するGoogleカレンダーIDを取得する <<セルC9(行9,列3)
const ss = SpreadsheetApp.getActiveSpreadsheet();
const mysheet1 = ss.getSheetByName("カレンダー転記用");
constc al = CalendarApp.getCalendarById(calId);

//▼データ取得範囲の指定
const lastRow = mysheet1.getDataRange().getLastRow();
const lastCol = mysheet1.getDataRange().getLastColumn();
console.log(lastRow);
console.log(lastCol);

//「日付」のデータ取得範囲の指定(B16~)
//getRange(16行目,2列目,●行分,列分)
const dateRange = mysheet1.getRange(16,2,lastRow-16,1); 
console.log(dateRange.getA1Notation());

//「①」~「④」のデータ取得範囲の指定 
//getRange(16行目,4列目,●行分,列分)
const eventRange1 = mysheet1.getRange(16,4,lastRow-16,1); //「①」セルD16(行16,列4)~ 
const eventRange2 = mysheet1.getRange(16,5,lastRow-16,1); //「②」セルE16(行16,列5)~
const eventRange3 = mysheet1.getRange(16,6,lastRow-16,1); //「③」セルF16(行16,列6)~
const eventRange4 = mysheet1.getRange(16,7,lastRow-16,1); //「④」セルG16(行16,列7)~

//「①登録処理」~「④登録処理」フラグのデータ取得範囲の指定 
const flagRange1 = mysheet1.getRange(16,8,lastRow-16,1);  //①済フラグ(セルH列)
const flagRange2 = mysheet1.getRange(16,9,lastRow-16,1);   //②済フラグ(セルI列)
const flagRange3 = mysheet1.getRange(16,10,lastRow-16,1); //③済フラグ(セルJ列)
const flagRange4 = mysheet1.getRange(16,11,lastRow-16,1); //④済フラグ(セルK列)

//▼各データを配列として取得する
const myDate = dateRange.getValues();   //「日付」(myDate)
const event1 = eventRange1.getValues();  //「①」(event1)
const event2 = eventRange2.getValues();  //「②」(event2)
const event3 = eventRange3.getValues();  //「③」(event3)
const event4 = eventRange4.getValues();  //「④」(event4)
const myflag1 = flagRange1.getValues();   //「①登録処理」(myflag1)
const myflag2 = flagRange2.getValues();  //「②登録処理」」(myflag2)
const myflag3 = flagRange3.getValues();  //「③登録処理」(myflag3)
const myflag4 = flagRange4.getValues();   //「④登録処理」(myflag4)

//「登録済フラグ」配列(myflag1~4)のデータ指定
//セルB16(行16、列2)を全ての配列の起点0とし、下に1行ずつ移動
for (let i = 0; i < myDate.length; i++){
const targetflag1 = myflag1[i][6]; //「①」起点B16から下にi行、右に6列
const targetflag2 = myflag2[i][7]; //「②」E列 起点B16から下にi行、右に7列
const targetflag3 = myflag3[i][8]; //「②」F列 起点B16から下にi行、右に8列
const targetflag4 = myflag4[i][9]; //「②」G列 F列 起点B16から下にi行、右に9列

//「①」~「④」予定の配列(event1~4)のデータ指定
const targetevent1 = event1[i][2]; //「日付」起点B16から下にi行、右に2列
const targetevent2 = event2[i][3]; //「日付」起点B16から下にi行、右に3列
const targetevent3 = event3[i][4]; //「日付」起点B16から下にi行、右に4列
const targetevent4 = event4[i][5]; //「日付」起点B16から下にi行、右に5列

//「日付」の配列(myDate)のデータ指定
const targetDate = myDate[i][0]; //「日付」起点B16から下にi行、右に0列

//「①」配列(event1)に格納するデータ取得
//セルH16に「登録済」の表示がある時は、無視
//フラグなしの時、セルD16~ 起点B16から右へ2
if (targetflag1 === "登録済") {
continue
}
console.log(targetevent1);
console.log(targetDate);

//カレンダーに予定登録し、、完了したらスプレッドシート「登録処理③」に「登録済」と記載する
cal.createAllDayEvent(targetevent1,targetDate);
mysheet1.getRange(i,8).setValue("登録済"); //H列に「登録済」と記載

//「②」の配列(event2)の取得位置の指定
//セルI16に「登録済」の表示がある時は、無視
//フラグなしの時、セルE16~ 起点B16から右へ3
if (targetflag2 === "登録済") {
continue
}
console.log(targetevent2);
console.log(targetDate);

//カレンダーに予定登録し、、完了したらスプレッドシート「登録処理②」に「登録済」と記載する
cal.createAllDayEvent(targetevent2,targetDate);
mysheet1.getRange(i,9).setValue("登録済"); //I列に「登録済」と記載

//「③」の配列(event3)の取得位置の指定
//セルI16に「登録済」の表示がある時は、無視
//フラグなしの時、セルF16~ 起点B16から右へ4
if (targetflag3 === "登録済") {
continue
}
console.log(targetevent3);
console.log(targetDate);

//カレンダーに予定登録し、、完了したらスプレッドシート「登録処理③」に「登録済」と記載する
cal.createAllDayEvent(targetevent3,targetDate);
mysheet1.getRange(i,10).setValue("登録済"); //J列に「登録済」と記載

//「④」の配列(event4)の取得位置の指定
//セルK16に「登録済」の表示がある時は、無視
//フラグなしの時、セルG16~ 起点B16から右へ5
if (targetflag4 === "登録済") {
continue
}
console.log(targetevent4);
console.log(targetDate);

//カレンダーに予定登録し、、完了したらスプレッドシート「登録処理④」に「登録済」と記載する
cal.createAllDayEvent(targetevent4,targetDate);
mysheet1.getRange(i,11).setValue("登録済"); //K列に「登録済」と記載

//▼ダイアログMsgの表示
Browser.msgBox("Googleカレンダーへの転記作業が完了しました。\n登録内容はカレンダー転記シートで確認してください。",Browser.Buttons.OK);
}
}

補足情報(FW/ツールのバージョンなど)

前回レクチャーから、回答内容を読み込み、理解したつもりでしたが、
いざ次の工程を自分で書き進めると、理解できていないと痛感します。
お忙しいところ申し訳ありませんが、回答は明日以降で大丈夫なので、
次は自力でもう少し先まで進められるよう、
どこの記載で失敗したのか、ビギナーでも分かる解説をいただけます
でしょうか?
お手数をおかけして申し訳ありません。

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

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

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

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

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

guest

回答1

0

ベストアンサー

いくつか根本的な指摘です。
参考になれば幸いです。

##1
まず、lastRowはデータが存在する最終行が入りますね。
すごく単純なケースを考えて、データが16行目の1行しかない場合、lastRowは16です。
その上で、eventRange1~4と、flagRange1~4を取得するロジックを、落ち着いて考えてみましょう。
getRangeの引数は最初の2つが開始位置、残りの二つは終了位置に関する値ですが、終了位置の行数はこのままでは正しくないことは判るでしょうか。

##2
targetflag1~4、targetevent1~4の取得処理を考えてみましょう。
予め、eventRangeやflagRangeで、列毎のレンジを指定しています。その上で、targetflagとtargeteventを取得するときに、なぜかB16から右に移動した列数を考慮しています。
この処理が必要か不要か、よく考えてみてほしいです。

##3
そもそもmyfragやeventがこの状態の時、一次元の配列なのか二次元の配列なのか確認することをお勧めします。

##4
結論として、現状のソースだとcal.createAllDayEventの引数には値が何も入っていないことになります。

cal.createAllDayEvent(undefined,undefined);

ためしにこの1行のソースを実行すると、同じエラーが発生すると思います。

##5
ソースの全文を開示していただいたので、回答者も助かるのですが、さすがにコメントの内容など、ちょっとセキュリティ事故的に怖いラインを超えているように感じます。予め、許可等を得たのであれば問題ないのですけれど、老婆心ながら地名・団体名・人名などはマスク(隠す)ことをお勧めします。

投稿2021/12/13 09:33

com.woody

総合スコア43

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

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

donguriko

2021/12/13 14:51 編集

com.woodyさま お忙しい中、回答ありがとうございます。 自分が全然理解できていないこと、改めて痛感しました。 1.  非エンジニア、ビギナーでも分かる例をありがとうございます。    どう考えればよいのかのヒントになりました。    lastRow-16ではなく、(正)lastRow-15だと理解しました。 2.3. ご指摘を受け、考えました。    日付(myDate)は一元配列。    予定①と登録済フラグ①は、登録済フラグ有無でデータ取得処理の有無が変わるので、    同一配列内で取得要。よって、二次元配列。    予定②、登録済フラグ②~予定④、登録済フラグ④も上に同じ、    と理解しました。    アドバイスで混乱していた頭の中が整理できました。    おかげさまで配列について、前より少し理解が深まった気がします。 4.  上記を踏まえコード修正し、実行ログを確認したところ、    スプレッドシート記載のテスト1~4が同じ数だけ確認できたので、配列として    データ取得できたと思います。    が、大変申し訳ありませんが、下のエラーが立ち、処理完結できませんでした。    もし可能でしたら併せて、下のエラーについてもアドバイス(解消のためのヒント)    をいただけないでしょうか?     知識不足で本当に申し訳ありません。 「Exception: The parameters (String,number[],number[]) don't match the method signature for CalendarApp.Calendar.createAllDayEvent.」    >>・createAllDayEventで予定名と日付しか指定していないのがダメですか?       optionの指定も必要??      ・日付(myDate)が数値として取得できていないのでエラーですか? この場合、どうすれば数値に変換できる? ※もし、修正後のコードの連携が必要な場合は再掲載しますのでご連絡ください。 5.  ご指摘ありがとうございます。本文と画像修正させていただきました。
com.woody

2021/12/13 15:38

配列の部分についてです。 lastRow関連については、その理解で正しいです。 予定①を例にすると、eventRange1の指定はD16から16-15で1行1列を範囲にしていますね。(21行目) 仮にデータが10行あれば25-15になり、10行1列の範囲になります。これは言い換えると、D列を16行目からデータが含まれている最下行まで「1列分」指定していることになります。 このセルのイメージがそのままevent1の配列のイメージになります。(10×1の配列、つまり一次元の配列になります)。 最終的にこの10×1の配列から、カウンタiでぐるぐる回しているfor文の回数繰り返しているループ内で、targetevent1を取得なさろうとしていますね。 myflagも同様です。 for文内部の代入右辺にいる配列の指定方法をまずどうにかしないといけないですね。 ここまで、理解が追い付くでしょうか。 次に、新たに発生したエラーについてですが、エラーを直訳すると、「関数に文字列、数字の配列、数字の配列を指定しているけど、この関数の引数の組み合わせにそんな組み合わせはないッス」と言われています。 おそらくcreateAllDayEventの日付の変数に数値の配列が入っているので、型が違うといわれているのですね。うまく配列から日付が取れていれば次の1行で型変換することができます。 ``` cal.createAllDayEvent(targetevent1, new Date(targetDate)); ``` ただ、エラーメッセージの通りに解釈すると、引数が3ついるように思われているので、そこは修正後のソースを見てみないと何とも言えないかもしれません。
donguriko

2021/12/13 16:03

com.woodyさま お忙しい中、コメントありがとうございます。 投稿後、再度考えたところ、2.3. で日付のみで1次元配列でデータ取得、と 回答しましたが、日付データと予定名を取得するのは、登録済フラグがない場合のみなので、 日付も同一配列として取得しないといけないのではないか、という気がしてきました。 また、eventRange1についてのご指摘とエラーメッセージの翻訳もありがとうございます。 明日以降、いただいたヒントを元に再度じっくり考えてみて、改めてお返事をさせていただきます。 お忙しい中、ビギナーにおつきあいいただき本当にありがとうございます。 独学苦戦中なので大変助かります。
donguriko

2021/12/18 13:31 編集

com.woodyさま (qnoirさま) 先日はお忙しい中、アドバイスありがとうございました。 ご教示いただいた内容を元に、数日 悩み苦戦しながら修正試みました。 <修正した内容> ・L列に予定データなし(土日祝)の分を配列から除外するための「対象外フラグ」追加 ・予定①はB16~L列までの二次元配列でデータ取得 [B列、D列、H列、L列] ・予定②もB16~L列までの二次元配列でデータ取得 [B列、E列、I列、L列] ・予定③もB16~L列までの二次元配列でデータ取得 [B列、F列、J列、L列] ・予定④もB16~L列までの二次元配列でデータ取得 [B列、G列、K列、L列] 配列でのデータ取得できました。 D列~G列データなしの時、L列に「対象外」のフラグ追記もできました。 カレンダーへの予定登録は、下の処理が未完のためスキップ中。 データ取得できたらスプレッドシートH列~K列に「登録済」フラグを追記もできました。 ありがとうございました。 (未完部) 配列からL列に「対象外」フラグありデータの除外ができず困っています。 新たに質問を立てさせていただきますので、お忙しいところ大変申し訳ありませんが、 非エンジニアビギナーでも理解できるレベルでヒントをいただけないでしょうか? https://teratail.com/questions/374476 回答は本日中でなくてよいです。 お忙しいところお手数をおかけいたしまして申し訳ありません。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.46%

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

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

質問する

関連した質問