web-dev-qa-db-ja.com

単一の列の最後の行を決定する

Cols AからHまでのデータを含むシートがあります。

データを含む列Aの最後の行を決定する必要があります(すべて連続しています-データ/行にギャップはありません)。

more列のデータ行がAよりも多い他の列にもデータがあるため、列Aのみを分離する必要があります。 (および/またはcol A内の範囲のみ)。

スプレッドシートレベルでこれを行うには、

=COUNTA(A2:A100)

ただし、Google Apps Scriptソリューションのすべての調査で、多数のi++ものを含む数十行のコードを含む複数の機能を実行するための要件のみを見つけたようです。 A1から直接オフセットします。

このメソッドを変更する列固有の方法はありますか?

var aLast = ss.getDataRange().getNumRows();

複雑なプロセスが必要な場合は、そのようにしてください。しかし、より簡単なソリューションを想像するのは難しい(さらに見つけるのはさらに難しい!)と思います。

誰かが私を啓発する(または私のバブルをポップする)ことを気にしますか?

46
5th4x4

JavaScriptのトリックを使用してはどうですか?

_var Avals = ss.getRange("A1:A").getValues();
var Alast = Avals.filter(String).length;
_

この答え からこのアイデアを借りました。 Array.filter() メソッドは、列Aのすべてのセルを含むAvals配列で動作します。ネイティブ関数のコンストラクターでフィルタリングすることにより、non -null要素。

これは単一の列でのみ機能します。範囲に複数の列が含まれる場合、filter()の結果にはすべての列からのセルが含まれるため、範囲の設定されたディメンションの外側になります。

119
Mogsdad

簡単な式はありませんが、考えることができますが、列Aの最後の行を見つけるために数十行のコードを必要としません。この単純な関数を試してください。他の関数=CountColA()を使用する通常の方法でセルで使用します

function CountColA(){
  var sheet = SpreadsheetApp.getActiveSheet();
  var data = sheet.getDataRange().getValues();
  for(var i = data.length-1 ; i >=0 ; i--){
    if (data[i][0] != null && data[i][0] != ''){
      return i+1 ;
    }
  }
}
11
Srik

これにより、列Aに基づいてシートの最後の行が取得されます。

function getLastDataRow(sheet) {
  var lastRow = sheet.getLastRow();
  var range = sheet.getRange("A" + lastRow);
  if (range.getValue() !== "") {
    return lastRow;
  } else {
    return range.getNextDataCell(SpreadsheetApp.Direction.UP).getRow();
  }              
}

これにより、@ mrityunjay-pandeyの部分的に正しい答えが修正されます。

この答えを拡張して最後の行と列を取得するには、次を使用できます。

function columnToLetter(column) {
  var temp, letter = '';
  while (column > 0) {
    temp = (column - 1) % 26;
    letter = String.fromCharCode(temp + 65) + letter;
    column = (column - temp - 1) / 26;
  }
  return letter;
}

function letterToColumn(letter) {
  var column = 0, length = letter.length;
  for (var i = 0; i < length; i++) {
    column += (letter.charCodeAt(i) - 64) * Math.pow(26, length - i - 1);
  }
  return column;
}

function getLastDataColumn(sheet) {
  var lastCol = sheet.getLastColumn();
  var range = sheet.getRange(columnToLetter(lastCol) + "1");
  if (range.getValue() !== "") {
    return lastCol;
  } else {
    return range.getNextDataCell(SpreadsheetApp.Direction.PREVIOUS).getColumn();
  }              
}

function getLastDataRow(sheet) {
  var lastRow = sheet.getLastRow();
  var range = sheet.getRange("A" + lastRow);
  if (range.getValue() !== "") {
    return lastRow;
  } else {
    return range.getNextDataCell(SpreadsheetApp.Direction.UP).getRow();
  }              
}

function run() {
  var sheet = SpreadsheetApp.getActiveSheet();
  var [startRow, lastRow] = [2, getLastDataRow(sheet)];
  var [startCol, lastCol] = [1, getLastDataColumn(sheet)];
}
5
Al Johri

逆の方法でこれを行うことができます。スプレッドシートの最後の行から開始して、値が得られるまで上に向かっていきます。これは、間にいくつかの空の行がある場合でも、すべての場合に機能します。コードは次のようになります。

var iLastRowWithData = lastValue('A');
function lastValue(column) {
  var iLastRow = SpreadsheetApp.getActiveSheet().getMaxRows();
  var aValues = SpreadsheetApp.getActiveSheet().getRange(column + "2:" + column + lastRow).getValues();

  for (; aValues[iLastRow - 1] == "" && iLastRow > 0; iLastRow--) {}
  return iLastRow;
}
5
Akash Garg

非常に大きなスプレッドシートの場合、このソリューションは非常に高速です。

function GoLastRow() {
  var spreadsheet = SpreadsheetApp.getActive();
  spreadsheet.getRange('A:AC').createFilter();
  var criteria = SpreadsheetApp.newFilterCriteria().whenCellNotEmpty().build();
  var rg = spreadsheet.getActiveSheet().getFilter().setColumnFilterCriteria(1, criteria).getRange();

  var row = rg.getNextDataCell (SpreadsheetApp.Direction.DOWN);  

  LastRow = row.getRow();

  spreadsheet.getActiveSheet().getFilter().remove();

  spreadsheet.getActiveSheet().getRange(LastRow+1, 1).activate();

};
2
Luciano Pivi

getDataRegion を使用しました

sheet.getRange(1, 1).getDataRegion(SpreadsheetApp.Dimension.ROWS).getLastRow()

これは、(OPの要求に従って)連続するデータに依存していることに注意してください。

1
Simon Birt

個人的に私は同様の問題を抱えており、このようなものに行きました:

function getLastRowinColumn (ws, column) {
  var page_lastrow = ws.getDataRange().getNumRows();
  var last_row_col = 0
  for (i=1; i<=page_lastrow;i++) {
    if (!(spread.getRange(column.concat("",i)).isBlank())) {last_row_col = i};
  }
  return last_row_col
}

Wsの行数を探し、列の各セルをループします。空でないセルを見つけると、last_row_col変数内のそのセルの位置を更新します。連続していない列を持ちながら、最後の行を把握できるという利点があります(列全体を調べている場合)。

0
jello195

別の回答を投稿するのに遅すぎることはありません。ここに私の最後のセルを見つけるスニペットがあります。私は主に速度に興味があります。約150,000行で使用しているDBでは、この関数は同じデータで(平均)0.53秒かかる@MogsdadエレガントなJSソリューションと比較して、ソリューションを見つけるのに(平均)0.087秒かかりました。両方の配列は、関数呼び出しの前にプリロードされました。再帰を利用してバイナリ検索を行います。 100,000行以上の場合、結果を返すのに15〜20ホップしかかからないことがわかります。

最初にコンソールでログをテストして、その動作を確認できるように、Log呼び出しを残しました。

/* @OnlyCurrentDoc */

function myLastRow() {

var ss=SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var colArray = ss.getRange('A1:A').getDisplayValues();  // Change to relevant column label and put in Cache
var TestRow=ss.getLastRow();
var MaxRow=ss.getMaxRows(); 

Logger.log ('TestRow = %s',TestRow);
Logger.log ('MaxRow = %s',MaxRow);

var FoundRow=FindLastRow(TestRow,MaxRow);

Logger.log ('FoundRow = %s',FoundRow);    

function FindLastRow(v_TestRow,v_MaxRow) {

/* Some Housekeeping/error trapping first
* 1) Check that LastRow doesn't = Max Rows. If so then suggest to add a few lines as this
* indicates the LastRow was the end of the sheet.
* 2) Check it's not a new sheet with no data ie, LastRow = 0 and/or cell A1 is empty.
* 3) A return result of 0 = an error otherwise any positive value is a valid result.
*/

 return   !(colArray[0][0]) ? 1                   // if first row is empty then presume it's a new empty sheet
        :!!(colArray[v_TestRow][0]) ? v_TestRow   // if the last row is not empty then column A was the longest
        : v_MaxRow==v_TestRow ? v_TestRow         // if Last=Max then consider adding a line here to extend row count, else
        : searchPair(0,v_TestRow);                // get on an find the last row
}

function searchPair(LowRow,HighRow){

var BinRow = ((LowRow+HighRow)/2)|0;   // force an INT to avoid row ambiguity

Logger.log ('LowRow/HighRow/BinRow = %s/%s/%s',LowRow, HighRow, BinRow);

/*   Check your log. You shoud find that the last row is always found in under 20 Hops.
 *   This will be true whether your data rows are 100 or 100,000 long.
 *   The longest element of this script is loading the Cache (ColArray)
 */

 return   (!(colArray[BinRow-1][0]))^(!(colArray[BinRow][0])) ? BinRow
        : (!(colArray[BinRow-1][0]))&(!(colArray[BinRow][0])) ? searchPair(LowRow,BinRow-1)
        : (!!(colArray[BinRow-1][0]))|(!!(colArray[BinRow][0])) ? searchPair(BinRow+1,HighRow)
        : false;   // Error
 }
}

/* The premise for the above logic is that the binary search is looking for a specific pairing, <Text/No text>
 * on adjacent rows.  You said there are no gaps so the pairing <No Text/Text> is not tested as it's irrelevant.
 * If the logic finds <No Text/No Text> then it looks back up the sheet, if it finds <Text/Text> it looks further
 * down the sheet.  I think you'll find this is quite fast, especially on datasets > 100,000 rows.
 */
0
DeeKay789

GetLastRow/getLastColumn関数を書き直して、行インデックスまたは列インデックスを指定しました。

function get_used_rows(sheet, column_index){
      for (var r = sheet.getLastRow(); r--; r > 0) {
        if (sheet.getRange(1, 1, sheet.getLastRow(), sheet.getLastColumn()).getCell(r, column_index).getValue() != ""){
          return r;
          break;
        }
      }
    }

function get_used_cols(sheet, row_index){
  for (var c = sheet.getLastColumn(); c--; c > 0) {
    if (sheet.getRange(1, 1, sheet.getLastRow(), sheet.getLastColumn()).getCell(row_index, c).getValue() != ""){
      return c;
      break;
    }
  }
}
0
Ashton Fei

Mogsdadソリューションからの更新、

var Avals = ss.getRange("A1:A").getValues();
var Alast = Avals.filter(function(r){return r[0].length>0});
0
Tin Trang

私は次の3つの関数を書き込もうとしましたが、さまざまなケースでテストできます。これは私がテストしたデータです:

enter image description here

関数getLastRow1およびgetLastRow2は列Bに対して0を返します関数getLastRow3は列Bに対して1を返します

ケースに応じて、ニーズに合わせて微調整します。

function getLastRow1(sheet, column) {
  var data = sheet.getRange(1, column, sheet.getLastRow()).getValues();

  while(typeof data[data.length-1] !== 'undefined'
     && data[data.length-1][0].length === 0){ 
    data.pop();
  }
  return data.length;
}

function test() {
  var sh = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Sheet6');
  Logger.log('Cách 1');
  Logger.log("Dòng cuối cùng của cột A là: " + getLastRow1(sh, 1));
  Logger.log("Dòng cuối cùng của cột B là: " + getLastRow1(sh, 2));
  Logger.log("Dòng cuối cùng của cột C là: " + getLastRow1(sh, 3));
  Logger.log("Dòng cuối cùng của cột D là: " + getLastRow1(sh, 4));
  Logger.log("Dòng cuối cùng của cột E là: " + getLastRow1(sh, 5));
  Logger.log('Cách 2');  
  Logger.log("Dòng cuối cùng của cột A là: " + getLastRow2(sh, 1));
  Logger.log("Dòng cuối cùng của cột B là: " + getLastRow2(sh, 2));
  Logger.log("Dòng cuối cùng của cột C là: " + getLastRow2(sh, 3));
  Logger.log("Dòng cuối cùng của cột D là: " + getLastRow2(sh, 4));
  Logger.log("Dòng cuối cùng của cột E là: " + getLastRow2(sh, 5));
  Logger.log('Cách 3');
  Logger.log("Dòng cuối cùng của cột A là: " + getLastRow3(sh, 'A'));
  Logger.log("Dòng cuối cùng của cột B là: " + getLastRow3(sh, 'B'));
  Logger.log("Dòng cuối cùng của cột C là: " + getLastRow3(sh, 'C'));
  Logger.log("Dòng cuối cùng của cột D là: " + getLastRow3(sh, 'D'));
  Logger.log("Dòng cuối cùng của cột E là: " + getLastRow3(sh, 'E'));

}

function getLastRow2(sheet, column) {
  var lr = sheet.getLastRow();
  var data = sheet.getRange(1, column, lr).getValues();

  while(lr > 0 && sheet.getRange(lr , column).isBlank()) {
    lr--;
  }

  return lr;
}

function getLastRow3(sheet, column) {
  var lastRow = sheet.getLastRow();
  var range = sheet.getRange(column + lastRow);
  if (range.getValue() !== '') {
    return lastRow;
  } else {
    return range.getNextDataCell(SpreadsheetApp.Direction.UP).getRow();
  } 
}

列数または最後の列のインデックスを取得するには:

var numColumns = sheet.getLastColumn()

行数または最後の行のインデックスを取得するには:

var numRows = sheet.getLastRow()

どこ

var sheet = SpreadsheetApp.getActiveSheet()
0
Ashish Verma
var Direction=SpreadsheetApp.Direction;
var aLast =ss.getRange("A"+(ss.getLastRow()+1)).getNextDataCell(Direction.UP).getRow();
0

これはラストローを回避する別の方法かもしれません。ニーズに合わせてコードをいじる必要があるかもしれません

    function fill() {
      var spreadsheet = SpreadsheetApp.getActive();
      spreadsheet.getRange('a1').activate();
      var lsr = spreadsheet.getLastRow();
      lsr=lsr+1;
      lsr="A1:A"+lsr;

      spreadsheet.getActiveRange().autoFill(spreadsheet.getRange(lsr), SpreadsheetApp.AutoFillSeries.DEFAULT_SERIES);
};
0
Tariq Khalaf