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

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

ただいまの
回答率

87.59%

GASで表示行のみ取得したい(フィルタ機能ではなく、hideRowsで非表示にした場合)

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,238

score 3

前提・実現したいこと

スプレッドシート上にデータベースを作成しております。
GASで検索条件に当てはまらない行をhideRowsにより非表示にする、自作検索機能を付けました。
※フィルタ機能による絞り込みではありません。

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

絞り込んだ後のデータのみを取得しコピペしたいのですがうまくいきません。

例えば、全データ数が10個あり、上から2,3,8行目のデータのみが表示されている状態があったとします。(1,4~7,9,10行目が非表示になっている)
ここでgetRange().getValues()により配列を取得すると2行目から8行目まで、7つのデータが入った配列が取得されてしまいます。

GASで、表示されている行のみを取得する方法ってあるのでしょうか?

2021/02/05追記
すみません、例がよくなかったようです…
イメージ説明
上図のように、実は取り出したい配列は「『15行目から最終行のうち』表示されている行」でした。

function test(){
  const sheet = SpreadsheetApp.getActiveSheet();
  const lastrow = sheet.getLastRow();
  const values = sheet.getRange(15,1,lastrow-14, 2).getValues();
  const show_values = values.filter((row,i) => !sheet.isRowHiddenByUser(i+15));
  console.log(show_values);
}


isRowHiddenByUserの引数を「i」から[i+15」に変えることで
やりたかったことが実現できました。

もう少々お聞きしてもよろしいでしょうか?
filterメソッドの引数(row,i)とisRowHiddenByUserとの関係をご教示いただけますでしょうか。
アロー式にまだ慣れていないので、functionだとどういう書き方となるのか
教えていただけると今の私でも理解できるかもしれません。

大変恐縮ではございますが、せっかくなのできちんと理解しておきたいと思うのです。
宜しくお願いいたします。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 1

checkベストアンサー

0

GASの質問なので、Google Apps Script のタグを付けた方が回答が得られます。

ご質問の件ですが、isRowHiddenByUser を使うと非表示判定ができるので、
これとfilterを組み合わせれば出来ます。

https://developers.google.com/apps-script/reference/spreadsheet/sheet?hl=ja#isrowhiddenbyuserrowposition

ByUserってあると手動のみっぽいですがGASで非表示にした行でも大丈夫です。

フィルタ機能以外で非表示にしている行なら true を返すので、
表示されている == 非表示ではない ってことですから !をつけてあげるのと、
配列は0スタートなので、行は +1 で取得する点だけ気を付ければ良いかと。

サンプルコード

function teratail_320127(){
  const sheet = SpreadsheetApp.getActiveSheet();
  const values = sheet.getRange(1,1,10,2).getValues();
  const show_values = values.filter((row,i) => !sheet.isRowHiddenByUser(i+1));
  console.log(show_values);
}

↓もう少し汎用性のある書き方に修正

function teratail_320127b(){
  const sheet = SpreadsheetApp.getActiveSheet();
  const startrow = 1; //取得を開始する行
  const values = sheet.getRange(startrow,1,sheet.getLastRow(),2).getValues();
  const show_values = values.filter((row,i) => !sheet.isRowHiddenByUser(i+startrow));
  console.log(show_values);
}

↓アロー関数使わない場合。あんま変わらないです。

function teratail_320127c(){
  const sheet = SpreadsheetApp.getActiveSheet();
  const startrow = 1; //取得を開始する行
  const values = sheet.getRange(startrow,1,sheet.getLastRow(),2).getValues();
  const show_values = values.filter(function(row,i){
   retun !sheet.isRowHiddenByUser(i+startrow);
  });
  console.log(show_values);
}

↓filterを使わず forループでやる場合。これが一番しっくりくるなら、それでもOK

function teratail_320127_d(){
  const sheet = SpreadsheetApp.getActiveSheet();
  const startrow = 1; //取得を開始する行
  const values = sheet.getRange(startrow,1,sheet.getLastRow(),2).getValues();

  let show_values =[];
  for(i=0; i<values.length; i++){
    if(!sheet.isRowHiddenByUser(i+startrow)){
      show_values.push(values[i])
    }
  };
  console.log(show_values);
}

引用テキスト①iは0からvalues.length-1までインクリメントされる
また、アロー式の引数である(row,i)のrowは何を指しているのでしょうか?

iは、その理解でOKです。valuesという配列の個々の要素が row で i がindex(ざっくり言えば順番)です。
いきなり宣言してない rowなんてのが出てくるんで、私も最初の頃は ??ってなりましたが、
これは別に適当にvaluesって配列の個々の要素を row っておいただけで、別に value でも、vでもなんでもよいのです。スプレッドシートで取得した二次元配列は行成分を指すので、個人的にはrowって置くことが多いです。

引用テキスト②!sheet.isRowHiddenByUserの値がtrueであればshow_values.push(values[i])のような操作がされるという理解でよいのでしょうか?
for ループのコードも書きましたが、その理解で大丈夫と思います。

慣れないうちは 普通にforでループさせる書き方でよいと思います。

だんだんカッコよく書きたい、もっと短いコードで書きたいってなってきたら、今回使った filterやmap,
reduceなんかを使うようになって、徐々に理解もしていきます。

配列の要素を一つずつ関数に入れていくイメージで、結局やってることはforと一緒ですから。

参考
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/filter

珍しくコードを多く書く回答してしまった。。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2021/02/05 22:48

    お世話になります。
    スプレッドシートの状態と、コードを追記いたしました。

    filterメソッドとその引数について追加でお聞きしたく存じます。

    const show_values = values.filter((row,i) => !sheet.isRowHiddenByUser(i+15));
    filterメソッドとその引数についての質問なのですが
    ①iは0からvalues.length-1までインクリメントされる
    ②!sheet.isRowHiddenByUserの値がtrueであればshow_values.push(values[i])のような操作がされる
    という理解でよいのでしょうか?
    また、アロー式の引数である(row,i)のrowは何を指しているのでしょうか?

    すみません、もう少しだけお付き合い頂けますと幸いです…。
    宜しくお願いいたします。

    キャンセル

  • 2021/02/06 22:07 編集

    回答に追記、補足説明を入れときました。ただ、私はエンジニアではないですし、ちゃんとに学んだわけではないので参考程度にお考え下さい。

    私も最初のうちは、Array.prototype のメソッドは理解するのに時間かかりましたが、似たようなコード書いてるうちに慣れて腹に落ちます。徐々に活用できそうな処理を forループを使わないコードに切り替えていけば良いです。

    キャンセル

  • 2021/02/06 22:52

    非常に丁寧なご解説、誠にありがとうございます。
    そうなんです、アロー式については「慣れてはないけど何となくわかる」程度だったのですが、
    宣言していない変数が急に出てきたところが理解できなくて…。

    また、for文での書き方のご解説もありがとうございました。
    「filterメソッドの働き」が理解できました。(内部では違う動きをしているのかもしれませんが)

    最後までお付き合いいただき本当にありがとうございました。
    今後とも何卒よろしくお願い申し上げます。

    キャンセル

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

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

関連した質問

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