見出し画像

【GAS】Sheetクラスを書き始めてみた(学習記録)

受講しているGAS講座の中で、スプレッドシートのシート内のある列のどのインデックスに、求める文字列が含まれるかどうかを返す関数を書く、という課題がありました。

これをきっかけに、クラスを書く練習として、シートの列と探す文字列を指定すると、そのインデックスを返すメソッドを持つクラスSheetを作成してみました。

まずは、課題に特化した最低限のクラスになっていますが、今後、少しずつ機能を追加したり、スマートな書き方を覚えたりして、より便利にしていけたらと思っています。

クラスの書き方については、現在受講中のノンプロ研GAS中級講座etau先生のクラス、K先生のノンプロ研ペアプロを参考にさせていただきました!ありがとうございました!

1.クラス化前の背景

ノンプロ研GAS中級講座で下記の課題が出たので、まずは(1)のように回答しました。

(著作権者の許諾のもと公開しています)

(1) 初期のコード(単一列を表す配列と文字列を渡すと、その文字列のインデックスを返す関数)

/** 単一列を表す二次元配列から文字列を探してインデックスを返す関数の実行関数(検証含む) */
function myFunction3_08_1() {
  
  //TAさん確認用データをアクティブシートにセット
  setTestData_();

  //単一列(例としてC列)を表す二次元配列をvaluesInAColumnに代入
  const valuesInAColumn = SpreadsheetApp.getActiveSheet().getRange('C:C').getValues();

  //インデックスの確認
  console.log(`二郎: ${getIndexInAColumn_(valuesInAColumn, '二郎')}`);
  console.log(`Bob: ${getIndexInAColumn_(valuesInAColumn, 'Bob')}`);

}

/** 
 * シートの単一列を表す二次元配列内で指定された文字列を探してそのインデックスを返す 
 * @param {Array} valsInACol – スプレッドシートの単一列を表す二次元配列
 * @param {string} targetStr – 探すべき文字列
 * @return {number} 探している文字列のインデックス(なければ-1)
 */
function getIndexInAColumn_(valuesInAColumn, targetStr) {
  const flattedValuesInAColumn = valuesInAColumn.flat();
  const index = flattedValuesInAColumn.indexOf(targetStr);
  return index;
}

/** TAさん確認用の値をアクティブシートにセットする関数 */
function setTestData_() {

  const testData = [
    //A列     B列    C列
    [['福岡県'], ['高橋'], ['零郎']],
    [['東京都'], ['佐藤'], ['一郎']],
    [['神奈川県'], ['山田'], ['二郎']],
    [['大阪府'], ['鈴木'], ['三郎']],
    [['北海道'], ['田中'], ['四郎']]
  ];

  SpreadsheetApp.getActiveSheet()
    .clear()
    .getRange(1, 1, testData.length, testData[0].length)
    .setValues(testData);
}

これで、希望の動作はしてくれるのですが、ある列の中から特定の文字列を探したい、という需要は時々ありそうですね。そのような場合、例えば対象の列がC:Cである、というのを、コード内で毎回指定するのは面倒です。

そこで、次に、列と文字列を引数の形で渡せばインデックスを返す、という関数を(2)として書いてみました。

(2) 一歩進めたコード(A1Notationによる列指定と文字列を渡すと、その文字列のインデックスを返す関数)

function myFunction3_08_2() {//実行関数
  setTestData2_();
  console.log(`二郎: ${getIndexInAColumn2('C:C','二郎')}`);
  console.log(`Bob: ${getIndexInAColumn2('C:C','Bob')}`);
}

/** 
 * アクティブシートの単一列の値を二次元配列として返す関数
 * @param {string} columnA1Notation – 列を指定するA1notation(例:'A:A')
 * @return {Array.<Array>} 指定した列に含まれるセルの値を要素とする二次元配列
 */
function getValuesInAColumn2(columnA1Notation) {
  const valuesInAColumn = SpreadsheetApp.getActiveSheet().getRange(columnA1Notation).getValues();
  return valuesInAColumn;
}

/** 
 * アクティブシートの単一列を表す二次元配列内の指定文字列のインデックスを返す関数
 * @param {string} columnA1Notation – 列を指定するA1notation(例:'A:A')
 * @param {string} targetStr – 探すべき文字列
 * @return {number} 探した文字列のインデックス(存在しなければ-1)
 */
function getIndexInAColumn2(columnA1Notation, targetStr) {
  const valuesInAColumn = getValuesInAColumn2(columnA1Notation);
  const flattedValuesInAColumn = valuesInAColumn.flat();
  const index = flattedValuesInAColumn.indexOf(targetStr);
  return index;
}

/** TAさんの確認用として、アクティブシートに値をセット */
function setTestData2_() {

  const testData = [
    //A列     B列    C列
    [['福岡県'], ['高橋'], ['零郎']],
    [['東京都'], ['佐藤'], ['一郎']],
    [['神奈川県'], ['山田'], ['二郎']],
    [['大阪府'], ['鈴木'], ['三郎']],
    [['北海道'], ['田中'], ['四郎']]
  ];

  SpreadsheetApp.getActiveSheet()
    .clear()
    .getRange(1, 1, testData.length, testData[0].length)
    .setValues(testData);
}

次に、練習のため、これをクラス化してみました。

2. クラス化

列指定のA1notation('C:C'など)と、検索対象の文字列を引数として渡すと、その列を表す二次元配列におけるその文字列のインデックスを返すメソッドを持つ、クラスSheetを作成してみました。

function myFunction3_08_class() {//実行関数
  setTestData_();
  const sheet = new Sheet(); //自作クラスSheetのインスタンスを生成して定数sheetに代入

  console.log(`二郎: ${sheet.getIndexInAColumn('C:C', '二郎')}`);//自作クラスSheetのgetIndexInAColumnメソッドを使用
  console.log(`Bob: ${sheet.getIndexInAColumn('C:C', 'Bob')}`);
  console.log(`福岡県: ${sheet.getIndexInAColumn('A:A', '福岡県')}`);
  console.log(`ニューヨーク: ${sheet.getIndexInAColumn('A:A', 'ニューヨーク')}`);


}

/** シートに関するクラス */
class Sheet {
  /**
   * @constructor
   * @param {SpreadsheetApp.sheet} sheet - 対象シートオブジェクト(デフォルト:アクティブシート)
   */
  constructor(sheet = SpreadsheetApp.getActiveSheet()) {
    this.sheet = sheet;
  }

  /** 組み込みのClass Sheet から委譲されたメソッド */
  getRange(...args) { return this.sheet.getRange(...args); }

  /** 
   * 単一列を表す二次元配列を返すメソッド
   * @param {string} columnA1Notation – 列指定のA1notation(例:'A:A')
   * @return {Array.<Array>} 指定された列を表す二次元配列
   */
  getValuesInAColumn(columnA1Notation) {
    const valuesInAColumn = this.sheet.getRange(columnA1Notation).getValues();
    return valuesInAColumn;
  }

  /** 
   * 単一列を表す二次元配列内の指定された文字列のインデックスを返すメソッド
   * @param {string} columnA1Notation – 列指定のA1notation(例:'A:A')
   * @param {string} targetStr – 探すべき文字列
   * @return {number} 探した文字列のインデックス(存在しなければ-1)
   */
  getIndexInAColumn(columnA1Notation, targetStr) {
    const valuesInAColumn = this.getValuesInAColumn(columnA1Notation);
    const flattedValuesInAColumn = valuesInAColumn.flat();
    const index = flattedValuesInAColumn.indexOf(targetStr);
    return index;
  }
}

/** TAさん確認用の値をアクティブシートにセットする関数 */
function setTestData_() {

  const testData = [
    //A列     B列    C列
    [['福岡県'], ['高橋'], ['零郎']],
    [['東京都'], ['佐藤'], ['一郎']],
    [['神奈川県'], ['山田'], ['二郎']],
    [['大阪府'], ['鈴木'], ['三郎']],
    [['北海道'], ['田中'], ['四郎']]
  ];

  SpreadsheetApp.getActiveSheet()
    .clear()
    .getRange(1, 1, testData.length, testData[0].length)
    .setValues(testData);
}

初めにも書いた通り、まずは、今回の演習課題の機能に特化した最低限の内容ですが、少しずつ、より便利にしていければと思っています。

例えば、ヘッダーの値を引数に受けてヘッダー列を割り出すメソッド群を追加すれば、A1Notationではなく、’都道府県’というふうに列を指定できるので、列が移動されても機能し続ける強いコードにできそうかな、、、?

今後も、少しずつですが、書き溜めていくつもりです。学習記録ですので、ご指摘などありましたらお寄せ頂けましたら嬉しいです。
お読みいただきありがとうございました。

この記事が気に入ったらサポートをしてみませんか?