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

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

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

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

配列

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

Q&A

解決済

2回答

3324閲覧

【GAS】配列で取得した複数データの合体について

donguriko

総合スコア30

Google スプレッドシート

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

配列

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

0グッド

0クリップ

投稿2021/09/26 10:22

編集2021/09/26 11:32

##![イメージ説明実現したいこと
非エンジニアのGASビギナーです。
お忙しいところ申し訳ありません、2点教えてください。
お返事は明日以降でも大丈夫です。

やりたいこと

スプレッドシートで1か月分(列)月~日×(行)6週の1か月分×12か月分の
表形式★のシフト表を作成予定。
イメージ説明

各日の入力欄は、担当ごとに4行×2列(AM、PM)の8つの入力欄に分かれています。
最終的はシフト表のデータをGASでGoogleカレンダーに「
「終日予定」として連携、登録したいと思っています。

が、表形式から直接カレンダーへの連携はハードルが高いので、
①表形式シフト表→別スプレッドシート☆にデータ転記。
②別スプレッドシート→カレンダー連携の2ステップで進めようと思っています。

☆年月を指定で縦方向の日数が可変する万年カレンダー式。
縦方向に1日~末日までの日付。
横方向に、担当ごとの転記欄を4列。
転記の際、表形式のAMデータとPMデータを合体させて担当ごとの転記欄に
データコピーさせたい。
イメージ説明

(参考)mysheet2
イメージ説明

今回①の入り口の部分で躓いています。

※最初から☆形式でシフト表作成した方が容易なのですが、
ユーザーから表形式がよいとの強い要望があり、苦戦中です。

 

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

①表形式シフト表から、水平方向で各担当のAM、PMデータを取得(一次元配列?)。
AM、PMデータを合体させ、☆スプレッドシートの1個のセルにデータコピー
させたいのですが、合体処理もしくは、コピー先の指定がうまくできていない
ようで下のエラーがたっています。
どこが間違えていて、どのように直せばよいか、アドバイスをいただけます
でしょうか?
配列で取得したデータにつき、以前もレクチャーいただいたのですが
理解が不十分のようで再度の質問となり申し訳ありません。
・joinができていない?
・配列データnakano4の定義がおかしい?
・getRange(3,12).setValue(nakano4); getRangeの定義がおかしい?

②今の案では、
各日の担当ごとの一元配列データごとに取得させようとしていますが、
1か月6週分のうち1週目分だけでかなりの量の記載となっています。
もし、担当1AMPM+担当2AMPM+担当3AMPM+担当4AMPM と4担当分をすべて
合体させて1つのデータとして団子にし、☆スプレッドシートに渡すことが
できれば、今の「泥臭い」やり方よりも団子方式の方がよいですか?
団子方式がおススメの場合は、大変申し訳ありませんが今の私の知識では
「やり方(二次元配列→1個の団子)」がわからなので、ビギナーでも自分で
調べながら進めていけそうなレベルでよいので、「やり方」のアドバイス、
ヒントをいただけないでしょうか?

※今回【条件4】に該当するケースでGAS実行 Exception: The parameters () don't match the method signature for SpreadsheetApp.Range.setValue. OriginalData @ 転記元シート作成.gs:292

該当のソースコード

全文記載します。(長文ご容赦を)

function OriginalData() { const ss = SpreadsheetApp.getActiveSpreadsheet(); const sh = ss.getActiveSheet(); const mysheet1 = ss.getSheetByName("転記元"); const mysheet2 = ss.getSheetByName("【メモ】日付算出"); const myMonth =mysheet2.getRange('D3').getValues(); const mySheetname= myMonth+"月"; const mysheet3 = ss.getSheetByName(mySheetname); //「日付算出」シート「1日の曜日」を取得 const firstDay = mysheet2.getRange('E8').getValues(); console.log(firstDay); //【条件1】 1日の曜日が「1:月」のとき「転記元」シート(L)にコピー //1週目 月曜-------------------------------- if (firstDay == 1) { //XX分 const copyValue1 = mysheet3.getRange('C6:D6').setValue(); const nakano1 = copyValue1.join; console.log(nakano1); mysheet1.getRange(3,12).setValue(nakano1); //XX分 const copyValue2 = mysheet3.getRange('C7:D7').setValue(); const nakanoMC1 = copyValue2.join; console.log(nakanoMC1); mysheet1.getRange(3,13).setValue(nakanoMC1); //XX分 const copyValue3 = mysheet3.getRange('C8:D8').setValue(); const Tele1 = copyValue3.join; console.log(Tele1); mysheet1.getRange(3,14).setValue(Tele1); //XX分 const copyValue4 = mysheet3.getRange('C99:D9').setValue(); const Holiday1 = copyValue4.join; console.log(Holiday1); mysheet1.getRange(3,15).setValue(Holiday1); //1週目 火曜-------------------------------- //XX分 const copyValue5 = mysheet3.getRange('E6:F6').setValue(); const nakano2 = copyValue5.join; console.log(nakano2); mysheet1.getRange(4,12).setValue(nakano2); //XX分 const copyValue6 = mysheet3.getRange('E7:F7').setValue(); const nakanoMC2 = array.join; console.log(nakanoMC2); mysheet1.getRange(4,13).setValue(nakanoMC2); //XX分 const copyValue7 = mysheet3.getRange('E8:F8').setValue(); const Tele2 = array.join; console.log(Tele2); mysheet1.getRange(4,14).setValue(Tele2); //XX分 const copyValue8 = mysheet3.getRange('E9:F9').setValue(); const Holiday2 = array.join; console.log(Holiday2); mysheet1.getRange(4,15).setValue(Holiday2); //1週目 水曜-------------------------------- //XX分 const copyValue9 = mysheet3.getRange('G6:H6').setValue(); const nakano3 = copyValue9.join; console.log(nakano3); mysheet1.getRange(5,12).setValue(nakano3); //XX分 const copyValue10 = mysheet3.getRange('G7:H7').setValue(); const nakanoMC3 = copyValue10.join; console.log(nakanoMC3); mysheet1.getRange(5,13).setValue(nakanoMC3); //XX分 const copyValue11 = mysheet3.getRange('G8:H8').setValue(); const Tele3 = copyValue11.join; console.log(Tele3); mysheet1.getRange(5,14).setValue(Tele3); //XX分 const copyValue12 = mysheet3.getRange('G9:H9').setValue(); const Holiday3 = copyValue12.join; console.log(Holiday3); mysheet1.getRange(5,15).setValue(Holiday3); //1週目 木曜-------------------------------- //XX分 const copyValue13 = mysheet3.getRange('I6:J6').setValue(); const nakano4 = copyValue13.join; console.log(nakano4); mysheet1.getRange(6,12).setValue(nakano4); //XX分 const copyValue14 = mysheet3.getRange('I7:J7').setValue(); const nakanoMC4 = copyValue14.join; console.log(nakanoMC4); mysheet1.getRange(6,13).setValue(nakanoMC4); //XX分 const copyValue15 = mysheet3.getRange('I8:J8').setValue(); const Tele4 = copyValue15.join; console.log(Tele4); mysheet1.getRange(6,14).setValue(Tele4); //XX分 const copyValue16 = mysheet3.getRange('I9:J9').setValue(); const Holiday4 = copyValue16.join; console.log(Holiday4); mysheet1.getRange(6,15).setValue(Holiday4); //1週目 金曜-------------------------------- //XX分 const copyValue17 = mysheet3.getRange('K6:L6').setValue(); const nakano5 = array.join; console.log(nakano5); mysheet1.getRange(7,12).setValue(nakano5); //XX分 const copyValue18 = mysheet3.getRange('K7:L7').setValue(); const nakanoMC5 = array.join; console.log(nakanoMC5); mysheet1.getRange(7,13).setValue(nakanoMC5); //XX分 const copyValue19 = mysheet3.getRange('K8:L8').setValue(); const Tele5 = copyValue19.join; console.log(Tele5); mysheet1.getRange(7,14).setValue(Tele5); //XX分 const copyValue20 = mysheet3.getRange('K9:L9').setValue(); const Holiday5 = array.join; console.log(Holiday5); mysheet1.getRange(7,15).setValue(Holiday5); ~略~ //【条件4】 1日の曜日が「4:木」のとき「転記元」シート(L)にコピー }if (firstDay == 4) { //1週目 木曜-------------------------------- //XX分 const copyValue13 = mysheet3.getRange('I6:J6').setValue(); const nakano4 = copyValue13.join; console.log(nakano4); mysheet1.getRange(3,12).setValue(nakano4); //★ここでエラー。 //XX分 const copyValue14 = mysheet3.getRange('I7:J7').setValue(); const nakanoMC4 = copyValue14.join; console.log(nakanoMC4); mysheet1.getRange(3,13).setValue(nakanoMC4); //XX分 const copyValue15 = mysheet3.getRange('I8:J8').setValue(); const Tele4 = copyValue15.join; console.log(Tele4); mysheet1.getRange(3,14).setValue(Tele4); //XX分 const copyValue16 = mysheet3.getRange('I9:J9').setValue(); const Holiday4 = copyValue16.join; console.log(Holiday4); mysheet1.getRange(3,15).setValue(Holiday4); //1週目 金曜-------------------------------- //XX分 const copyValue17 = mysheet3.getRange('K6:L6').setValue(); const nakano5 = array.join; console.log(nakano5); mysheet1.getRange(4,12).setValue(nakano5); //XX分 const copyValue18 = mysheet3.getRange('K7:L7').setValue(); const nakanoMC5 = array.join; console.log(nakanoMC5); mysheet1.getRange(4,13).setValue(nakanoMC5); //XX分 const copyValue19 = mysheet3.getRange('K8:L8').setValue(); const Tele5 = copyValue19.join; console.log(Tele5); mysheet1.getRange(4,14).setValue(Tele5); //XX分 const copyValue20 = mysheet3.getRange('K9:L9').setValue(); const Holiday5 = array.join; console.log(Holiday5); mysheet1.getRange(4,15).setValue(Holiday5); //【条件5】 1日の曜日が「5:金」のとき「転記元」シート(L)にコピー }if (firstDay == 5) { //1週目 金曜-------------------------------- //XX分 const copyValue17 = mysheet3.getRange('K6:L6').setValue(); const nakano5 = array.join; console.log(nakano5); mysheet1.getRange(3,12).setValue(nakano5); //XX分 const copyValue18 = mysheet3.getRange('K7:L7').setValue(); const nakanoMC5 = array.join; console.log(nakanoMC5); mysheet1.getRange(3,13).setValue(nakanoMC5); //XX分 const copyValue19 = mysheet3.getRange('K8:L8').setValue(); const Tele5 = copyValue19.join; console.log(Tele5); mysheet1.getRange(3,14).setValue(Tele5); //XX分 const copyValue20 = mysheet3.getRange('K9:L9').setValue(); const Holiday5 = array.join; console.log(Holiday5); mysheet1.getRange(3,15).setValue(Holiday5); //【条件6】 1日の曜日が「6:土」「7:日」のとき何もしない }else{ return;} }

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

GASの知識が浅いため、ビギナーでも理解できるよう解説いただけると
助かります。

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

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

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

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

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

退会済みユーザー

退会済みユーザー

2021/09/26 10:37

文章とコードだけですとシートのイメージがつかみにくいので、各シートの画像も掲載していただくことは可能でしょうか?
donguriko

2021/09/26 10:41

ご連絡ありがとうございます。 画像、了解です。IT度が低くて恐縮ですが、教えてください。 画像、どのようにして貼り付ければよいですか? プリントスクリーンで取得した画像、どこかにベタ貼りすればよいですか? お手数ですが、手順ご教示いただけますか? レベルが低くて申し訳ありません。。。。
donguriko

2021/09/26 10:49

了解です。トライしてみます。
donguriko

2021/09/26 11:18

すみません、技術が足りず。。。 うまく貼れていません。しかも貼られている位置もおかしいですね。 申し訳ありません。
退会済みユーザー

退会済みユーザー

2021/09/26 11:36

画像貼り付けの件ありがとうございました。改めて内容確認しますのでお待ちください。
donguriko

2021/09/26 11:43

1枚目の画像の下の余白が残ってしまい、申し訳ありません。。 もし、再度掲載等必要であればご連絡ください。 お忙しいところ画像掲載手順までレクチャーいただきありがとうございました。 よろしくお願いいたします。
guest

回答2

0

ベストアンサー

※回答欄に書き込める文字数をオーバーするため、先日の続きをこの回答欄に記載します。

--- 

(2)「二次元配列→1個の団子」のやり方

②今の案では、各日の担当ごとの一元配列データごとに取得させようとしていますが、

1か月6週分のうち1週目分だけでかなりの量の記載となっています。
もし、担当1AMPM+担当2AMPM+担当3AMPM+担当4AMPM と4担当分をすべて
合体させて1つのデータとして団子にし、☆スプレッドシートに渡すことが
できれば、今の「泥臭い」やり方よりも団子方式の方がよいですか?

結論からいうと「Yes」(団子方式の方がよい)です。
現状の書き方だと、シートのレイアウトに変更が生じた場合、コード上の変更しなければならない部分が多岐にわたり、メンテナンスが非常に面倒です。
その分バグが残っている可能性も高くなります。
(すでに33行目で、「'C9:D9'」とすべきところが「'C99:D9')」になってしまっています)

ではどのようにするかですが、下記のような流れになります。
・シフト表のカレンダー範囲を getValues()で2次元配列で取り込む。(データA)

・データAを、規則性に従って日付とシフトデータを紐づけた配列にし、表☆に書き込む。
(このとき、mysheet2 から取得した1日の曜日や月の日数・週数データも利用可能)

下記に、考え方を記します。
(一番最後に全体コードを載せています。途中の説明はそれらの一部を変えたものになっています)
(前提として、getValues()/setValues()と2次元配列に関する基礎的な知識は必須です。たとえば、「GAS 2次元配列」で検索して出てくる上位のサイト等を参考にされるとよいかと思います)

  1. シフト表全体を二次元配列に読み込む。

まず、シフト表のC4:N39の範囲を、getRange("C4:N39").getValues() として、
二次元配列に取り込みます。
(ここではテストのため、シフト表の最初から最後まで、1始まりの数字で埋めています。●月1日が火曜日以降に始まる場合は後述。)
イメージ説明

js

1 shiftTable = mysheet3.getRange("C4:N39").getValues();

こうすることで、 変数 shiftTable に、 シフト表のC4からN39までのデータが
二次元配列で格納されます。

  1. 各日付欄の位置の規則性を見つける

次に、取得した二次元配列 shiftTable から、各日付欄を最初から順番に取得していく方法を考えましょう。

たとえば「9」のセルは、二次元配列の0始まりのインデックスで 6行目、2列目 にあります。
したがって shiftTable[6][2] とすればアクセスできます。
イメージ説明

この考え方を手掛かりにして、1から順番に、日付欄の行/列インデックスを並べると、下記のように格納されていることが分かります。

日付欄-> [行][列] ※ 行、列は 0始まりのインデックス -------------- 1 -> [0][0] 2 -> [0][2] 3 -> [0][4] 4 -> [0][6] 5 -> [0][8] 6 -> [0][10] 7 -> [0][11] 8 -> [6][0] 9 -> [6][2]  10 -> [6][4] 11 -> [6][6] 12 -> [6][8] 13 -> [6][10] 14 -> [6][11] 15 -> [12][0] 16 -> [12][2] 17 -> [12][4] 18 -> [12][6] 19 -> [12][8] 20 -> [12][10] 21 -> [12][11] ・ ・ ・ 36 -> [30][0] 37 -> [30][2] 38 -> [30][4] 39 -> [30][6] 40 -> [30][8] 41 -> [30][10] 42 -> [30][11]

以上より、日付欄を1つずつ増やしていった場合・・・

<平日>
・各週で「列」が0~8まで、2個飛ばしで続く。(0, 2, 4, 6, 8)
・週が変わるとき、「行」は前の週の「行」に6を足した数字になる。 (0, 6, 12, 18, 24, 30)
・「行」は各週で固定した数字。

<休日>
・土曜は金曜の列+2
・日曜は土曜は列+1

という規則になっていることが分かります。
イメージ説明

これをプログラムで表現するため、二重ループを使用します。
(二重ループとは、ループの中にループがあるものです)

行をx, 列をy、 としたとき、日付欄を順に出力するコード例は下記になります。

text

1function 日付欄順番表示テスト() { 2 3 // シフト表のデータを2次元配列で取得 4 const ss = SpreadsheetApp.getActiveSpreadsheet(); 5 const mysheet3 = ss.getSheetByName("4月"); // シフト表シート 6 const shiftTable = mysheet3.getRange("C4:N39").getValues(); 7 8 // 行/列インデックス用の変数 9 let x, y; 10 11 // 週が変わるとき、「行」は前の週の「行」に6を足した数。 12 for (x = 0; x <= 30; x += 6) { 13 14 // 「列」が0~8まで、2個飛ばしで続く。 15 for (y = 0; y <= 8; y += 2) { 16 17 Logger.log( shiftTable[x][y] ); 18 } 19 //(ループを抜けた時点でy=10になっている) 20 // 土曜 21 Logger.log( shiftTable[x][y] ); 22 // 日曜 23 Logger.log( shiftTable[x][y+1] ); 24 } 25}

上記のコードを実行した場合、下記になります。
日付欄が、最初(左上)から、順番に取得できていることが分かると思います。

text

1出力結果: 2------ 31 42 53 64 75 86 9...略 1040 1141 1242
  1. 各日のスケジュールデータの取り込み

各日で「担当1AMPM+担当2AMPM+担当3AMPM+担当4AMPM と4担当分をすべて

合体させる」

日付欄(各日付の左上)のセルの行/列インデックスが [x][y]とすると、各セルの位置は、

担当1AM = [x+2][y]、  担当1PM = [x+2][y+1]
担当2AM = [x+3][y]、  担当2PM = [x+3][y+1]
担当3AM = [x+4][y]、  担当3PM = [x+4][y+1]
担当4AM = [x+5][y]、  担当4PM = [x+5][y+1]

となっています(下図)。
イメージ説明

したがって、任意の1日の「担当1AMPM 担当2AMPM 担当3AMPM 担当4AMPM 」のスケジュール
下記のように作ればよいことになります。

js

1daily = [ 2 shiftTable[x+2][y] + shiftTable[x+2][y+1], // 担当1AMPM 3 shiftTable[x+3][y] + shiftTable[x+3][y+1], // 担当2AMPM 4 shiftTable[x+4][y] + shiftTable[x+4][y+1], // 担当3AMPM 5 shiftTable[x+5][y] + shiftTable[x+5][y+1] // 担当4AMPM 6];
  1. 取得した各日付のスケジュールを1か月分まとめる。

2.では、各日付欄を最初から最後まで順番に取得するやり方を説明しました。
3.では、各日付の中にあるスケジュールを取り込むやり方を説明しました。

ここでは2と3を組み合わせて、1か月分のスケジュールを1つにまとめたいと思います。

具体的には、1か月分のスケジュールを格納するための配列schedulesを用意し、このschedules配列に先ほど取得した各日のスケジュールデータ(daily)を追加していくようにします。

土日はスケジュールがないため、空のスケジュールを追加するようにしています。

js

1function シフト表データ取り込みテスト() { 2 // シフト表のデータを2次元配列で取得 3 const ss = SpreadsheetApp.getActiveSpreadsheet(); 4 const mysheet3 = ss.getSheetByName("4月"); 5 const shiftTable = mysheet3.getRange("C4:N39").getValues(); 6 7 // シフトテーブルの各日付のスケジュールを格納するための配列。 8 const schedules = []; 9 10 // 行/列インデックス用の変数 11 let x, y; 12 13 // 二重ループで日付欄を順番に読み取る。 14 for (x = 0; x <= 30; x += 6) { 15 for (y = 0; y <= 8; y += 2) { 16 // 1日のスケジュールの読み取り 17 const daily = [ 18 shiftTable[x+2][y] + shiftTable[x+2][y+1], // 担当1AMPM 19 shiftTable[x+3][y] + shiftTable[x+3][y+1], // 担当2AMPM 20 shiftTable[x+4][y] + shiftTable[x+4][y+1], // 担当3AMPM 21 shiftTable[x+5][y] + shiftTable[x+5][y+1] // 担当4AMPM 22 ]; 23 // 配列に1日のスケジュールを追加する。 24 schedules.push(daily); 25 } 26 // 土日は予定がない為、空のスケジュールを追加する。 27 schedules.push(['','','','']); // 土曜 28 schedules.push(['','','','']); // 日曜 29 } 30 Logger.log(schedules); 31}

 
上記を実行すると、ログウィンドウにschedules 配列の内容が表示されます。

[[(MC_AM)なし(PM)なし, , (MC_AM)なし, ], [(終日)なし, , , ], [, (MC_AM)なし, , ], [(終日)なし(PM)なし, , , ], [, (PM)なし, , ], [, , , ], [, , , ], [, , , ], [(終日)なし(MC_AM)なし, , (PM)なし, ], [(終日)なし(MC_AM)なし, .....

複雑に見えますが、これを中の[]ごとに改行すると、下記のように、シフト表の各日付欄をそのまま転記したものになっていることが分かります。
(7日×6週の42個)

[ [(MC_AM)なし(PM)なし, , (MC_AM)なし, ], [(終日)なし, , , ], [, (MC_AM)なし, , ], [(終日)なし(PM)なし, , , ], [, (PM)なし, , ], [, , , ], [, , , ], [, , , ], [(終日)なし(MC_AM)なし, , (PM)なし, ], [(終日)なし(MC_AM)なし, , ],  ..... ];

 
あとは、この配列を☆シートの表に書き込めばよさそうですが、実はもう一手間かける必要があります。

月の始まりが、月曜日でない場合の対応

たとえば下図のように月の最初の1日が月曜ではなく木曜日の場合、schedules配列の最初の3日間は、空白のデータが入っていることになります。また、末日(30日)以降も、空白のデータが入っています。
イメージ説明
上図の状態で シフト表データ取り込みテスト() を実行し、ログ内容を整理すると、、

[ [,,,], [,,,], //最初の3マスはデータがない [,,,], [(終日)なし(PM)なし, , ,] // 最初の日(1日)のデータ ......... [,,,], [,,,], // 月末日(28日~31日)以降は空白データが続く [,,,] ]

のようになっています。

☆シートに書き込むときは、これら先頭と末尾の空白データを除外して書き込まなければなりません。

対象月が何曜日から始まるか
対象付きの日数がいくつか
は 日付算出シート から取得できますから、
日付算出シート からこれらの情報を取得し、
schedules配列から 必要なデータだけ切り取るという処理を行います。

・配列から一部を切り取るには、slice()関数を使います。

slice(開始インデックス, 開始インデックス+個数)

で、配列の [開始インデックス] から 指定した個数までの要素までを切り取ることができます。

slice関数の使用例: const arr = ['a', 'b' ,'c', 'd', 'e', 'f']; // arr から、0始まりのインデックス2('c')から 4('e') までの3個を 切り取る const f = arr.slice(2, 5); // 終了インデックスは、開始インデックス+切取り個数を指定する。 Logger.log(f); 出力結果: ['c', 'd', 'e']

繰り返しになりますが、ここでは、
対象月が何曜日から始まるか
対象月の日数がいくつか
を 日付算出シート から取得し、slice関数を使って
schedules配列から 必要なデータだけ切り取るという処理を行おうとしています。

たとえば木曜始まりの場合、「4」番目の項目から始まります。
slice()関数はゼロ始まりで開始インデックスを指定するので、4-1=3 を開始インデックスとします。
(0,1,2,3 -> 4番目は「3」)
また 4月の日数は「30」なので、終了インデックスは 3+30=33 となります。

一般化すると、

js

1schedules.slice(対象月の始まり曜日-1 ,対象月の始まり曜日-1 + 日数)

とすればちょうど1か月分のスケジュールデータの配列が切り取れます。

これをプログラムにすると下記のようになります。

mysheet2 = ss.getSheetByName("【メモ】日付算出"); const firstDay = mysheet2.getValue("E8"); // 対象月が何曜日から始まるか(1:月曜日、2:火曜日...) const daysOfMonth = mysheet2.getValue("C14"); // 対象月の日数 // schedules配列から、先頭と末尾の空白を除いた1か月分の予定を切り取る const monthlySchedules = schedules.slice(firstDay - 1, firstDay - 1 + daysOfMonth);

 
5. ☆シートへの書き込み

あとは、上記で取得したmonthlySchedulesを、☆に書き込めばいいです。

・書き込み開始セル:L3番地(=3行目,12列目)
・行数:先ほど取得した日数(daysOfMonth)
・列数:4列(L列~O列まで)

なので、
monthlySchedules を「☆シート」に書き込むためのコードは下記のようになります。
(これは前の質問の復習にもなっていますね)

js

1mysheet1 = ss.getSheetByName("転記元"); 2 3// [左上:L3セル、行数:月の日数、列数:4列]の範囲に書き込む。 4mysheet1.getRange(3, 12, daysOfMonth, 4).setValues(monthlySchedules);

以上(1)~(5)をまとめた全体コードは下記になります。

js

1function outputSchedules() { 2 const ss = SpreadsheetApp.getActiveSpreadsheet(); 3 const sh = ss.getActiveSheet(); 4 const mysheet1 = ss.getSheetByName("転記元"); // 「☆シート」 5 const mysheet2 = ss.getSheetByName("【メモ】日付算出"); 6 const myMonth = mysheet2.getRange('D3').getValues(); 7 const mySheetname = myMonth+"月"; 8 const mysheet3 = ss.getSheetByName(mySheetname); 9 10 // シフト表のデータを2次元配列で取得 11 const shiftTable = mysheet3.getRange("C4:N39").getValues(); 12 13 // シフトテーブルの各日付のスケジュールを格納するための配列。 14 const schedules = []; 15 16 // 行/列インデックス用の変数 17 let x, y; 18 19 // 二重ループで日付欄を順番に読み取る。 20 for (x = 0; x <= 30; x += 6) { 21 for (y = 0; y <= 8; y += 2) { 22 // 1日のスケジュールの読み取り 23 const daily = [ 24 shiftTable[x+2][y] + shiftTable[x+2][y+1], // 担当1AMPM 25 shiftTable[x+3][y] + shiftTable[x+3][y+1], // 担当2AMPM 26 shiftTable[x+4][y] + shiftTable[x+4][y+1], // 担当3AMPM 27 shiftTable[x+5][y] + shiftTable[x+5][y+1] // 担当4AMPM 28 ]; 29 // 配列に1日のスケジュールを追加する。 30 schedules.push(daily); 31 } 32 // 土日は予定がないので、空のスケジュールを追加する。 33 schedules.push(['', '', '', '']); // 土曜 34 schedules.push(['', '', '', '']); // 日曜 35 } 36 37 //「日付算出」シートから「1日の曜日」を取得 (1:月曜、2:火曜、3:水曜...) 38 const firstDay = mysheet2.getRange('E8').getValue(); 39 40 //「日付算出」シートから、月の日数を取得 41 const daysOfMonth = mysheet2.getRange('C14').getValue(); 42 43 // schedules配列から、先頭と末尾の空白を除いた1か月分の予定を切り取る 44 const monthlySchedules = 45 schedules.slice(firstDay - 1, firstDay - 1 + daysOfMonth); 46 47 // ☆シートの [左上:L3セル、行数:月の日数、列数:4列]の範囲に書き込む。 48 mysheet1.getRange(3, 12, daysOfMonth, 4).setValues(monthlySchedules); 49 50 Logger.log("処理が完了しました"); 51}

投稿2021/09/29 11:38

編集2021/09/29 21:58
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

donguriko

2021/09/30 11:26

qnoirさま さきほどコメント投稿したつもりが、投稿できていなさそうなので再度投稿します。 お忙しい中、初心者向け解説、ありがとうございます。 こんなに丁寧な解説を記載するのは相当お手間だったに違いないという事は ビギナーの私にもわかります。 本当にここまでしていただいてありがとうございます。ただただ感謝です。 記載いただいた内容、残念ながらじっくり読み込まないと理解できないので、 これから時間をかけて読み込みたいと思います。 もし、わからないことがでてきたら又質問をさせてください。 本当にありがとうございました!!!
退会済みユーザー

退会済みユーザー

2021/09/30 11:29

ご丁寧にありがとうございます。わかりにくいところがあれば何なりと聞いてください(時間のある時だけしか対応できないので、お待たせするかもしれませんが)
guest

0

(1)現状発生しているエラーを回避する方法について
処理として、シフト表からデータを読み取り、文字列を連結し、☆のカレンダー様式シートにデータを書き込もうとされていますが、現状のエラーは前半のデータ読み取り段階で発生しています。
(修正したコードは後半に掲示していますので、先にそちらを参照していただけると、どこが間違いなのかわかりやすいと思います。)

  • getValues()について

イメージ説明

上の図のように、「C6:D6」のように複数のセル範囲の値読み取る場合、
setValue()ではなく、 getValues()を使用します。(複数形の「s」がつきます)

setValue()は、単一の値または数式の書き込みに使うものです。
setValues()は、配列に格納した複数の値または数式の書き込みに使います。

getValue()は、1つのセルの読み取りに使います。
getValues()は、複数のセル範囲の読み取りに使います。

(※厳密には、setValues,getValuesはそれぞれ単一の値の書き込み/読み込みも可、
setValueは単一の値/数式を複数範囲に書き込むことは可)

  • join()について

文字列を連結するには join()関数を使います。
関数なので、「join」の後に括弧()が必要です。
括弧をつけないと、「function join() { [native code] }」のような呪文のような文字列が返ってきます。

「.join()」を使うと、配列の各要素がカンマで連結された文字列が返ってきます。
(一次元配列にしたうえで、「()」の中に文字列を入れることで連結する文字を変えることができますが、ここでは説明を省略します)

例: var s = ['abc', 'def', 'ghi']; var renketsu = s.join()); // 「配列.join()」 という使い方をする。 Logger.log(renketsu); >>> abc,def,ghi // カンマで連結された文字列が返ってくる。

上記を踏まえてコードを直すと下記のようになります。
一部だけ示していますが、他の部分も同様に直してください。

diff

1function OriginalData() { 2 3(略) 4//「日付算出」シート「1日の曜日」を取得 5const firstDay = mysheet2.getRange('E8').getValues(); 6console.log(firstDay); 7 8//【条件1】 1日の曜日が「1:月」のとき「転記元」シート(L)にコピー 9//1週目 月曜-------------------------------- 10if (firstDay == 1) { 11//XX分 12-const copyValue1 = mysheet3.getRange('C6:D6').setValue(); 13+const copyValue1 = mysheet3.getRange('C6:D6').getValues(); 14-const nakano1 = copyValue1.join; 15+const nakano1 = copyValue1.join(); 16console.log(nakano1); 17mysheet1.getRange(3,12).setValue(nakano1); 18//XX分 19(略) 20-const copyValue4 = mysheet3.getRange('C99:D9').setValue(); 21+const copyValue4 = mysheet3.getRange('C9:D9').getValues(); // 33行目 22(以下略)

 

(2)「二次元配列→1個の団子」のやり方

②今の案では、各日の担当ごとの一元配列データごとに取得させようとしていますが、

1か月6週分のうち1週目分だけでかなりの量の記載となっています。
もし、担当1AMPM+担当2AMPM+担当3AMPM+担当4AMPM と4担当分をすべて
合体させて1つのデータとして団子にし、☆スプレッドシートに渡すことが
できれば、今の「泥臭い」やり方よりも団子方式の方がよいですか?

結論からいうと「Yes」(団子方式の方がよい)です。
現状の書き方だと、シートのレイアウトに変更が生じた場合、コード上の変更しなければならない部分が多岐にわたり、メンテナンスが非常に面倒です。
その分バグが残っている可能性も高くなります。
(すでに33行目で、「'C9:D9'」とすべきところが「'C99:D9')」になってしまっています)

ではどのようにするかですが、下記のような流れになります。
・シフト表のカレンダー範囲を getValues()で2次元配列で取り込む。(データA)

・データAを、規則性に従って日付とシフトデータを紐づけた配列にし、
表☆に書き込む。(このとき、mysheet2 から取得した1日の曜日や月の日数・週数データも利用可能)

前提として、getValues()の2次元配列に関する基礎的な知識は必須です。
たとえば、「GAS 2次元配列」で検索して出てくる上位のサイト等を参考にされるとよいかと思います。

データAの規則性と加工に関する部分をわかりやすく解説するにはかなり時間がかかるので、一旦ここで筆をおきます。(コードで表現するのはさほど時間はかからないのですが・・)。
後日、回答を編集して追記します。

投稿2021/09/26 15:37

編集2021/09/26 21:30
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

donguriko

2021/09/27 13:18

qnoirさま、お忙しい中、丁寧な解説ありがとうございます。 (1)getValue()、getValues()  setValue()、setValues() の解説、ビギナーでもとても分かりやすいです。  また、Joinは後ろに()をつける必要あり、ですね。覚えます。 派生して「初歩の初歩」で恐縮ですが、get rangeの使い方についても教えてください。  実は少し頭が混乱気味です。  範囲指定の方法ですが、以下の理解で正しいですか?  ・単一セルなら(row,column)表記でも、('C1')の表記でもOK  ・複数セル範囲なら(row,column,numRows,numColumns)の表記でも('A1:C3')の表記でもOK  どちらを使った方がいい、こういう時はこっちを使わないとダメ等の「きまり」はありますか?  それとも好きな方を使えばよいですか?? (2)団子方式の方がよい。アドバイスありがとうございます。  お忙しい中、初心者向け解説のお手間をかけてしまい申し訳ありません。  解説は急ぎませんので、(その間に getValues()の2次元配列に関する  基礎的な知識の自習をしますので)、どうぞよろしくお願いたします。  いつも親切丁寧な解説、本当にありがとうございます。
退会済みユーザー

退会済みユーザー

2021/09/27 13:29

> 範囲指定の方法ですが、以下の理解で正しいですか? > ・単一セルなら(row,column)表記でも、('C1')の表記でもOK > ・複数セル範囲なら(row,column,numRows,numColumns)の表記でも('A1:C3')の表記でもOK その理解でOKです。 どちらを使った方がよい、等のきまりは特にありません。プログラミングの際に、使いやすい方を使えばよいと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問