回答編集履歴

3

md

2019/06/28 06:47

投稿

macaron_xxx
macaron_xxx

スコア3191

test CHANGED
@@ -390,7 +390,7 @@
390
390
 
391
391
 
392
392
 
393
- >2 row1[6] = arr[0][9]; この部分がいまいち理解できませんでした 
393
+ > 2 row1[6] = arr[0][9]; この部分がいまいち理解できませんでした 
394
394
 
395
395
  この部分はどのような役割を果たしているのでしょうか?
396
396
 
@@ -402,7 +402,7 @@
402
402
 
403
403
 
404
404
 
405
- >3 etData.lengthは貼り付ける行数
405
+ > 3 etData.lengthは貼り付ける行数
406
406
 
407
407
  setData[0].lengthは貼り付ける列数になる理由・・・
408
408
 

2

質問への回答

2019/06/28 06:47

投稿

macaron_xxx
macaron_xxx

スコア3191

test CHANGED
@@ -20,7 +20,7 @@
20
20
 
21
21
  //コピー先のスプレットシートを取得する
22
22
 
23
- var ss_copyTo = SpreadsheetApp.openById('xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx);
23
+ var ss_copyTo = SpreadsheetApp.openById('xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx');
24
24
 
25
25
  var sheet_copyTo = ss_copyTo.getSheetByName('シート2'); //コピー先のスプレットシートの中のシート名
26
26
 
@@ -369,3 +369,67 @@
369
369
 
370
370
 
371
371
  わからない部分があれば。
372
+
373
+
374
+
375
+ # 追記2 - わからない部分への回答
376
+
377
+ > 1 今回使っているreduce関数と前回使っていただいたmap関数は役割的にかなり近いものがあると調べてみて感じたのですが今回reduce関数を使用した理由等があればお聞きしたいです
378
+
379
+
380
+
381
+ mapとreduceは全然違います。
382
+
383
+ そもそもmapは配列を返すのに対して、reduceはなんでも返せます。
384
+
385
+ (reduceのリファレンス例でも数値を返しています。)
386
+
387
+ mapはその性質上、元となる配列の長さ(今回の場合は行数)と作成される配列の長さが一致します。
388
+
389
+ このため今回はmapは使えません。⇒reduceを使っています。
390
+
391
+
392
+
393
+ >2 row1[6] = arr[0][9]; この部分がいまいち理解できませんでした 
394
+
395
+ この部分はどのような役割を果たしているのでしょうか?
396
+
397
+
398
+
399
+ ここは結構雑にやっちゃってるので、わかりにくいですが、`arr`(コピー元のデータ)のJ1を代入しています。
400
+
401
+ つまり、"先払い金","差額"っていうやつですね。
402
+
403
+
404
+
405
+ >3 etData.lengthは貼り付ける行数
406
+
407
+ setData[0].lengthは貼り付ける列数になる理由・・・
408
+
409
+
410
+
411
+ ここはすんなり理解してもらいたかったですが、
412
+
413
+ SpreadsheetのgetValuesやsetValuesでは2次元配列を扱います。
414
+
415
+ `[[1,2,3],[1,2,3],[1,2,3]]`←こんな感じ
416
+
417
+
418
+
419
+ そのため、今回もreduceで2次元配列を作成しています。
420
+
421
+ (配列にrow(配列)をpushしています。)
422
+
423
+ なので、`setData`の`length`は行数ということです。
424
+
425
+ また`setData`の各row(`setData[0]`や`setData[N]`も)は列数になります。
426
+
427
+ かならず各rowの長さは一致させなければいけません。
428
+
429
+ ```javascript
430
+
431
+ /* OK */ [[1,2,3],[1,2,3],[1,2,3]]
432
+
433
+ /* NG */ [[1,2,3],[1,2],[1,2,3],[1,2,3,4]]
434
+
435
+ ```

1

解説を追記

2019/06/28 06:46

投稿

macaron_xxx
macaron_xxx

スコア3191

test CHANGED
@@ -91,3 +91,281 @@
91
91
  }
92
92
 
93
93
  ```
94
+
95
+
96
+
97
+ # 追記 - 解説
98
+
99
+ ```javascript
100
+
101
+ //コピー元のスプレットシートを取得する
102
+
103
+ var ss = SpreadsheetApp.getActiveSpreadsheet();
104
+
105
+ var ss_copyFrom = ss.getSheetByName("シート1");
106
+
107
+ var fromData = ss_copyFrom .getDataRange().getValues(); // データは全部取る
108
+
109
+
110
+
111
+ //コピー先のスプレットシートを取得する
112
+
113
+ var ss_copyTo = SpreadsheetApp.openById('xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx);
114
+
115
+ var sheet_copyTo = ss_copyTo.getSheetByName('シート2'); //コピー先のスプレットシートの中のシート名
116
+
117
+ var toData = sheet_copyTo.getDataRange().getValues(); // データは全部取る
118
+
119
+ ```
120
+
121
+ 基本的に、スプレッドシートの値は`getDataRange().getValues()`で全部取得してしまう。
122
+
123
+ `getValue()`する度にAPIが実行され、速度がどんどん低下していくため。
124
+
125
+ `for`の中で`getValue()`するのはご法度で、エディタでも警告がでる。
126
+
127
+
128
+
129
+ また今回は質問の回答にあった
130
+
131
+ > シート2のE~H列、K~N列は2行目のこの行は使わないとしていた行に固定の内容があって、コピーなどが終わった後にドラックで引っ張ってくるようなイメージ
132
+
133
+
134
+
135
+ から、コピーする時点でE~H列、K~N列に2行目の値をいれておくためにコピー先のデータも取得している。
136
+
137
+
138
+
139
+ ---
140
+
141
+
142
+
143
+ ```javascript
144
+
145
+ var tmpRow = (function(baseArr) {
146
+
147
+ var arr = [];
148
+
149
+ for (var i = 3; i < 15; i++) {
150
+
151
+ arr.push(baseArr[i]);
152
+
153
+ }
154
+
155
+ return arr;
156
+
157
+ })(toData[1]);
158
+
159
+ ```
160
+
161
+ `tmpRow`はコピー先の行のテンプレートとして作成。
162
+
163
+ `toData[1]`でコピー先の2行目を渡し、D(3)からO(14)列の値が入った配列を用意した。
164
+
165
+ ```javascript
166
+
167
+ // tmpRowイメージ
168
+
169
+ ["(D2の値)","(E2の値)","(F2の値)",....,"(O2の値)"]
170
+
171
+ ```
172
+
173
+
174
+
175
+ ---
176
+
177
+
178
+
179
+ ```javascript
180
+
181
+ var setData = fromData.reduce(function(acc, cur, idx, arr) {
182
+
183
+ if(idx !== 0) {
184
+
185
+ var row1 = tmpRow.concat();
186
+
187
+ row1[0] = cur[11];
188
+
189
+ row1[5] = cur[9];
190
+
191
+ row1[6] = arr[0][9];
192
+
193
+ row1[11] = cur[9];
194
+
195
+ acc.push(row1);
196
+
197
+
198
+
199
+ if(cur[10] !== "") {
200
+
201
+ var row2 = tmpRow.concat();
202
+
203
+ row2[0] = cur[11];
204
+
205
+ row2[5] = cur[10];
206
+
207
+ row2[6] = arr[0][10];
208
+
209
+ row2[11] = cur[10];
210
+
211
+ acc.push(row2);
212
+
213
+ }
214
+
215
+ }
216
+
217
+ return acc;
218
+
219
+ }, []);
220
+
221
+ ```
222
+
223
+ おそらくここが一番の難所であり、肝となる部分。
224
+
225
+ コピー先に貼り付けるデータを作成している。
226
+
227
+
228
+
229
+ `Array.prototype.reduce()`がわからない場合は、[リファレンス](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce)で確認。
230
+
231
+ ※リファレンスを読んでもけっこう理解できないかもしれない。色々試してみるのがよいかも。
232
+
233
+
234
+
235
+ 簡単に解説すると
236
+
237
+ ```javascript
238
+
239
+ var setData = fromData.reduce(function(acc, cur, idx, arr) {
240
+
241
+ /* 省略 */
242
+
243
+ }, []);
244
+
245
+ ```
246
+
247
+ この一番最後にある`[]`(初期値)にどんどん行を追加していって、データを作っているイメージ
248
+
249
+ `reduce`は`fromData`の行がループ的に`cur`で渡ってくる。
250
+
251
+ `acc`はループでどんどん行が追加された最新のもの(←よくわかんない表現TT)
252
+
253
+ `idx`はループのインデックス
254
+
255
+ `arr`は`fromData`自身
256
+
257
+
258
+
259
+ その上で中の処理
260
+
261
+ ```javascript
262
+
263
+ if(idx !== 0) {
264
+
265
+ var row1 = tmpRow.concat();
266
+
267
+ row1[0] = cur[11];
268
+
269
+ row1[5] = cur[9];
270
+
271
+ row1[6] = arr[0][9];
272
+
273
+ row1[11] = cur[9];
274
+
275
+ acc.push(row1);
276
+
277
+
278
+
279
+ if(cur[10] !== "") {
280
+
281
+ var row2 = tmpRow.concat();
282
+
283
+ row2[0] = cur[11];
284
+
285
+ row2[5] = cur[10];
286
+
287
+ row2[6] = arr[0][10];
288
+
289
+ row2[11] = cur[10];
290
+
291
+ acc.push(row2);
292
+
293
+ }
294
+
295
+ }
296
+
297
+ return acc;
298
+
299
+ ```
300
+
301
+
302
+
303
+ `idx===0`のときは、コピー元のヘッダ行のため、スルー。
304
+
305
+ それ以外の場合は`row1`を`tmpRow`からディープコピー。
306
+
307
+ ```javascript
308
+
309
+ row1 = tmpRow;
310
+
311
+ ```
312
+
313
+ としてしまうと、シャローコピーとなり、`row1`を変更した際に`tmpRow`も変更されてしまうためNG
314
+
315
+ ```javascript
316
+
317
+ row1 = Array.from(tmpRow);
318
+
319
+ ```
320
+
321
+ とするのがベストなのだが、GASでは`Array.from()`が使えないため、`Array.prototype.concat()`を使うことで、擬似的にディープコピーしている。
322
+
323
+
324
+
325
+ あとはコピーした行に対して、変更をかけるD,I,J,O列に値を代入して`acc`に行追加。
326
+
327
+ ここまでがJ列の先払金の処理。(J列は必ず入っている想定)
328
+
329
+
330
+
331
+ 次にK列が入っている場合のみ、J列と同様のことをおこなう。(値のみK列に変更)
332
+
333
+
334
+
335
+ `fromData`(コピー元シート)の1行ごとにループをまわして、J列→K列(あれば)という形で新しい行列データを作成していく。
336
+
337
+
338
+
339
+ ---
340
+
341
+
342
+
343
+ 最後に
344
+
345
+ ```javascript
346
+
347
+ sheet_copyTo.getRange(sheet_copyTo.getLastRow() + 1, 4, setData.length, setData[0].length).setValues(setData);
348
+
349
+ ```
350
+
351
+ で一気にコピー先シートにデータの貼り付け。
352
+
353
+
354
+
355
+ `sheet_copy.getLastRow() + 1`で最終行の下からスタート
356
+
357
+ `4`はD列
358
+
359
+ `setData.length`は貼り付ける行数
360
+
361
+ `setData[0].length`は貼り付ける列数
362
+
363
+ をそれぞれ指す
364
+
365
+
366
+
367
+ ---
368
+
369
+
370
+
371
+ わからない部分があれば。