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

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

ただいまの
回答率

90.33%

GASで各スプレッドシートよりセルの情報を集める

解決済

回答 1

投稿

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

amnoskanae

score 7

前提・実現したいこと

 前提

わたしはプログラミング初心者で、毎日ググりながら、問題を解決を考える程度のスペックの持ち主です。
本当に初心者なので、全くいいプログラミングの書き方ではないのは百も承知ですが、だからこそ皆さんのお力をお借りできればと思います。

 現状

現在社内の業務効率化に向けてスプレッドシートの改良を行っています。
社員が毎月各スプレッドシートで勤務時間を記入するシートがあり、各々から数値を確認し、確からしいかチェックした後に、一括管理するスプレッドシートにコピペをします。

そのコピペの作業が面倒なので、一括管理するスプレッドシートからボタン一つで各スプレッドシートの特定のセルにある情報を吸い上げて、一覧にそのまま数値を反映させたいと思います。

数値を吸い上げるまではかなったのですが、それらを一括管理するスプレッドシートに反映させるのに困っています。

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

エラーは出ていませんが、吸い上げたデータを配列に格納したいのですが、どうすればいいのかわかりません。

該当のソースコード

以下で、各社員のスプレッドシートが保存されているファイルを先月の月末の数字で名付けてあり、各社員のファイルは、作業月報_社員の苗字_月末の数字という名付け方です。

 function paidHolidaySet(){

  //社員を配列データとして格納
    var users = [ 'akito','fujisawa','inoue']; 
    var file_names = users.map(function(element) {

  //月末lmld=lastmonthlastday
  var dt = new Date();
  var lmld = new Date(dt.getFullYear(), dt.getMonth(), 0)

  // YYYYMMDD形式に変換
  var year_str = lmld.getFullYear();
  var month_str = lmld.getMonth()+ 1; // monthはなんと0-11
  var day_str = lmld.getDate();

  var month_str = ('0' + month_str).slice(-2);
  var day_str = ('0' + day_str).slice(-2);

  var format_str = 'YYYYMMDD';
  format_str = format_str.replace(/YYYY/g, year_str);
  format_str = format_str.replace(/MM/g, month_str);
  format_str = format_str.replace(/DD/g, day_str);

       return "作業月報_" + element + "_" + format_str; 
   });

   Logger.log(file_names);

        //フォルダーの中にある各ファイルにアクセスし、IDを取得
        var fileIDs = file_names.map(function(element){
           //ファイル名をユーザー名・月末で指定する
            //月末lmld=lastmonthlastday
           var dt = new Date();
           var lmld = new Date(dt.getFullYear(), dt.getMonth(), 0)

            // YYYYMMDD形式に変換
           var year_str = lmld.getFullYear();
           var month_str = lmld.getMonth()+ 1; // monthはなんと0-11
           var day_str = lmld.getDate();

           var month_str = ('0' + month_str).slice(-2);
           var day_str = ('0' + day_str).slice(-2);

           var format_str = 'YYYYMMDD';
           format_str = format_str.replace(/YYYY/g, year_str);
           format_str = format_str.replace(/MM/g, month_str);
           format_str = format_str.replace(/DD/g, day_str);
       //フォルダーの名前を指定
           var folderName = format_str ; 
           folderName = folderName.toString();

    //フォルダー名をドライブから検索し、IDを取得
           var folderID = DriveApp.getFoldersByName(folderName).next().getId();
 // Logger.log(folderID);
            return DriveApp.getFolderById(folderID).getFilesByName(element).next().getId();
    });
 Logger.log(fileIDs);


    //スプレッドシートアプリから取得したIDのスプレッドシートを起動し、アクティブシート取得
    var sheet = fileIDs.map(function(element){
     var sht=  SpreadsheetApp.openById(element);
        var st = sht.getActiveSheet();
         var array = [];
         var latestPaidHour = st.getRange( 1,1 ).getValues();
         latestPaidHour = latestPaidHour.toString();
      for ( var i = 0; i < latestPaidHour.length; i++ ){
        return array.push(latestPaidHour);
      }
      Logger.log(latestPaidHour);
    });
 Logger.log(sheet);

}

試したこと

最初は配列一つで、その中で作業が完結されるような書き方をしたかったのですが、何度やっても失敗したので、配列の数値を、

1.ファイル名の指定
2.ファイルIDの指定
3.各ファイルにアクセスして、指定のセルから数値を取得し、配列に格納

という順序で更新していくような形にしてみました。
最後の段階で、指定のセルから数値を取得し、Logger.logには各値を反映できていますが、それを配列に格納できません。
もしくは配列でなくとも、そのまま数値を現在開いている一括管理するスプレッドシートの指定の位置にそのままsetValueできれば問題はないです。

しかし、いろいろと調べては試してみるも、何が合っていて、間違っているのか区別がつかず、途方に暮れています。

また動作が少し遅いのでもっとシンプルな文にならないかなと思いながらも、どう改良できるかわかりません。

わからないことだらけで、申し訳ございませんが、どうぞよろしくお願いいたします。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 1

checkベストアンサー

0

現在の質問だと問題点が見えないです

  • 「数値を吸い上げるまではかなった」
    Logger.log(latestPaidHour);は動作してないはず。
    となるとLogger.log(sheet);が出力をしているはずで、これは配列を出力しているはず(mapの結果なので)
    であれば、「Logger.logには各値を反映できていますが、それを配列に格納できません」というのは整合性が取れません。
    →出力サンプルを提示いただけませんか。

  • 書き込み
    これを開いているシートなんだと思いますが、概念的には

SpreadsheetApp.getActiveSheet.getRange(1,1,sheet.length, sheet[0].length).setValues(sheet);


なので、形をあわせるだけ。

  • 動作が少し遅いのでもっとシンプルな文
    シンプルにしたりmapを組み合わせることでは早める効果は今回の例では薄いと思います。遅い原因は毎回ファイルとフォルダを名前から探したり、各ファイルから値を拾ってきたりするところなので、原理的に大幅な改善が難しいです。
    ジャストアイデアですが、↓のような対策をすると改善が期待できると思います。
  1. ファイル名の重複がおこらないようなルール(同姓だと重複する)にして、ファイルidの探査をやめる
    (余談ですが、getFilesByNameはフォルダ無視して検索してくれるので、もし姓が重複しないなら、DriveApp.getFilesByNameとすることで、現在のコードでもフォルダを無視して取得可能なはず)
  2. ファイルidやフォルダidはあらかじめ、管理シートに記録しておく(プログラムを書く)
    (こちらは絶対量としてかかる時間はへらないのですが、例えば夜間に時間のかかる処理を逃がしておいて、ユーザが操作する時には応答を速くするという考えです。まあそもそも全体を夜間に処理したらいいのかもしれませんが)

今のコードの意味を(多分)破綻させないように縮約してみました。

function paidHolidaySet(){

  //社員を配列データとして格納
  var users = [ 'akito','fujisawa','inoue']; 
  var fileIDs = users.map(function(element) {

    //月末lmld=lastmonthlastday
    var dt = new Date();
    var lmld = new Date(dt.getFullYear(), dt.getMonth(), 0)

    // YYYYMMDD形式に変換
    var year_str = lmld.getFullYear();
    var month_str = lmld.getMonth()+ 1; // monthはなんと0-11
    var day_str = lmld.getDate();

    var month_str = ('0' + month_str).slice(-2);
    var day_str = ('0' + day_str).slice(-2);
    return "作業月報_" + element + "_" + year_str + month_str + day_str; 
  })
  .map(function(element){
    //フォルダー名をドライブから検索し、IDを取得
    var folderID = DriveApp.getFoldersByName(element).next().getId();
    // Logger.log(folderID);
    return DriveApp.getFolderById(folderID).getFilesByName(element).next().getId();
  });
 Logger.log(fileIDs);

  //スプレッドシートアプリから取得したIDのスプレッドシートを起動し、アクティブシート取得
  var sheet = fileIDs.map(function(element){
    var sht=  SpreadsheetApp.openById(element);
    var st = sht.getActiveSheet();
    var array = [];
    var latestPaidHour = st.getRange( 1,1 ).getValue(); //here getValuesをgetValueに変更
    latestPaidHour = latestPaidHour.toString();
    Logger.log(latestPaidHour);
    return latestPaidHour; //here forの意味がなさそうなのでやめた
  });
 SpreadsheetApp.getActiveSheet.getRange(1,1,1,sheet.length).setValues([sheet]);
 //here 最初の1,1はA1。3つめの1は、どうも1回の操作で横一列しか取らないっぽい。ので固定値。
 Logger.log(sheet);
}

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2019/02/04 12:47

    何度もお返事いただき本当に助かります。
    無事数値を指定の場所に入れることができました!
    https://qiita.com/ShishidoToru/items/0ab9de4ea281df9358f4
    こちらも参考にしつつ、やってみました。
    papinianus 様のおかげで、新たに多くのことを学べました。この調子で色々と実際にGASなどを動かしながら、プログラミングの勉強に力を入れてまいります。
    誠にありがとうございました!

    キャンセル

  • 2019/02/04 12:51

    その引用リンクの件、あとから気付いてsetValues([sheet])と[]をつけました。もし的外れだったら無視してください。

    キャンセル

  • 2019/02/04 13:36

    ありがとうございます!
    なるほど、変換せずともそのように[]をつけるだけでいいんですね。
    シンプルなプログラミング文が書けるように日々邁進します。

    キャンセル

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

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

同じタグがついた質問を見る