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

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

ただいまの
回答率

89.10%

スプレッドシートでgetValuesで取得した二次元配列の処理について

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 86

sawa

score 727

スプレッドシートでgetValuesで取得した二次元配列の処理について教えてください。
なお、エラーが出る等の質問ではなく、より良い(正しい?)書き方の指南をいただきたいというお願いです。

以下のコードは 日にち毎のシートに分かれているデータを集計シートに統合する処理で、日付が古いものがシート番号の後ろのほうに来ている為、古い方から for文で データを取得しています。

集計シートの A列には 通し番号(3行目にタイトル行があり、データは4行目から)
集計シートの B列に取得したデータが入っていたシート名を 入れるようにしています。

元々はシートのデータ取得、貼付け、シート名取得、貼付け を forで回してたのですが、処理速度向上と関数での配列処理の勉強の為、 mapunshiftを使って 2次元配列の各要素の最初に シート名を追加と、そのデータを concat で結合することで、貼付け処理を最後の1回にしています。

質問としては、

  1. Data.map(function(arr){  の処理の箇所ですが、本当はアロー関数で書きたいのですが、unshiftが返り値がないため、書き方がわからず funciton を使って記述しています。こういった処理をアロー関数でより短く書くことは可能でしょうか?

  2. for文の最後の処理 var Array = Array.concat(Data2); ですが、こちらは逆に pushでの追加と違って返り値が欲しい為、このような書き方となっています。理解不足ですが、const ではうまくいかない為です。ただ、ネット上では varを使うケースは殆どないという記事を見たことがあり、書き方として正しくないのでは?と気になっています。
    このような for文で 配列を結合していく場合の書き方として、より良いものがあれば教えてください。

3. 最後の.setFormula("=SEQUENCE(COUNTA(B4:B))")ですが、単に集計シートのA列に連番をふりたいというだけなのですが、上記の二次元配列の処理に組み込むよい方法があれば知りたいです。

以上、よろしくお願いいたします。

function Sheetsummary() {


  const SS = SpreadsheetApp.getActiveSpreadsheet();
  const sheets = SS.getSheets();
  const sheetcount = sheets.length;
  const SumSheet = SS.getSheetByName("集計");

  //最初に集計シートの該当範囲をクリア
  SumSheet.getRange(4,1,SumSheet.getLastRow(),20).clearContent();

  var Array =[];

  for(i=sheetcount-1 ; i > 0 ; i=i-1){
    const sheetName =  sheets[i].getSheetName();
    const DataHigh = sheets[i].getLastRow()-3;
    const Data = sheets[i].getRange(4,2,DataHigh,8).getValues();

    const Data2 = Data.map(function(arr){
      arr.unshift(sheetName);
      return arr;
      });

    var Array = Array.concat(Data2);

    }

    const TRow = SumSheet.getLastRow()+1;
    SumSheet.getRange(TRow,2,Array.length,9).setValues(Array);

    SumSheet.getRange(4,1).setFormula("=SEQUENCE(COUNTA(B4:B))");

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+1

一個一個解決しちゃうと、ツギハギになってしまうような気もしますが、一応一つずつ回答しておきます。

  1. unshiftを使わずに記述します。
const Data2 = Data.map(arr => [sheetName, ...arr]);

2.pushしましょう。(なんで返り値がほしいのかがわからないです。)

const values = [];

for(i=sheetcount-1 ; i > 0 ; i=i-1){
  /* 省略 */
  values.push(...Data2);
}

3.これでいいなら初期化(クリア)しなきゃいいんじゃないですか?

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/06/30 16:04

    macaron_XXX様
    ありがとうございます。3つとも回答いただき助かります。3は確かにおっしゃる通りですね。
    最初のクリアする範囲を変更することで対応しました。

    1、2に関しては、私が ... の使い方を理解してない故に 質問のような記述になった次第です。
    ちなみに この... は、使ってるケースを見たことはあるのですが、検索でもうまく引っかからず、読み方もよくわからない為、自分の中で消化できていません。解説されているサイト等あれば 教えていただければ幸いです。

    キャンセル

  • 2020/06/30 16:07

    キャンセル

  • 2020/06/30 16:18

    早速ありがとうございます。活用できるケースが多々ありそうなので、読み込んで色々試したいと思います。

    キャンセル

+1

こんな感じでしょうか。

function q273985() {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const sheets = ss.getSheets();
  const sumSheetName = '集計';
  const sumSheet = ss.getSheetByName(sumSheetName);

  //最初に集計シートの該当範囲をクリア
  const lastRow = sumSheet.getLastRow();
  if (lastRow > 4) {
    sumSheet.getRange(4, 2, lastRow - 3, 19).clearContent();
  }

  const data = [];

  sheets.reverse().forEach(sheet => {
    const sheetName = sheet.getSheetName();
    if(sheetName !== sumSheetName) {
      const dataRow = sheet.getLastRow();
      data.push(...(sheet.getRange(4, 2, dataRow - 3 , 8).getValues().map(arr => [sheetName, ...arr])));
    }
  });
  Logger.log(data);
  sumSheet.getRange(4,2, data.length, 9).setValues(data);
}

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/06/30 17:33

    全体手直しありがとうございます。

    なるほど。reverse()を使うと sheetsの配列の並びが逆転するので、forEach で後ろのシートから順に処理が出来るのですね。そして1文で私のやりたかった配列処理を一気にやって pushしていくと。ご提示いただければ読解はなんとか出来るようになってきたのですが、まだまだ自分でこう書けるまでは遠そうです。勉強になりました。

    キャンセル

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

  • ただいまの回答率 89.10%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる