确定单个列中的最后一行

时间:2013-07-13 16:42:48

标签: google-apps-script google-sheets

我有一张包含cols AH的数据的工作表。

我需要确定列A中包含数据的最后一行(它们都是连续的 - 数据/行中没有间隙)。

其他列中的数据还有多行数据行而不是列A,因此我只需要隔离列A。 (和/或只是col A内的范围)。

我可以使用

在电子表格级别执行此操作
=COUNTA(A2:A100)

然而,在我对Google Apps脚本解决方案的所有研究中,我似乎发现需要执行包含数十行代码的多种功能 - 包括大量i++内容...我能做什么通过直接从A1抵消来减少复杂性。

是否可能采用特定于列的方法来修改此方法?

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

如果需要一个复杂的过程,那就这样吧。但我觉得很难想象(甚至更难找到!)一个更简单的解决方案。

有人关心启发我(或弹出我的泡泡)吗?

22 个答案:

答案 0 :(得分:115)

如何使用JavaScript技巧?

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

我从this answer借用了这个想法。 Array.filter()方法在Avals数组上运行,该数组包含A列中的所有单元格。通过对本机函数的构造函数进行过滤,我们只返回非null元素。

这仅适用于单个列;如果范围包含多个列,则filter()的结果将包括来自所有列的单元格,因此超出范围的填充维度。

答案 1 :(得分:11)

虽然没有直接的公式,但我可以想到,它不需要几十行代码来找出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 ;
    }
  }
}

答案 2 :(得分:4)

更新 2021 - 也考虑空单元

接受的答案以及大多数答案(如果不是全部)都有一个共同的限制,对于问题的所有者(他们有连续的数据)但对于未来的读者来说可能不是这种情况。

  • 也就是说,如果所选列之间包含空单元格,则接受的答案将给出错误的结果。

例如,考虑这个非常简单的场景:

enter image description here

接受的解决方案会给出 4,而正确答案是 6

解决方案:

使用 index 方法查找从数组末尾开始的第一个非空值的 reverse

const ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName('Sheet1')
const lrow = sh.getLastRow();
const Avals = sh.getRange("A1:A"+lrow).getValues();
const Alast  = lrow - Avals.reverse().findIndex(c=>c[0]!='');

答案 3 :(得分:4)

你可以通过反向进行。 从电子表格的最后一行开始,直到你获得一些价值。即使您之间有一些空行,这也适用于所有情况。 代码如下所示:

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;
}

答案 4 :(得分:4)

假设基于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 :(得分:2)

旧线程,但我找到了一种似乎有效的简单方法

ws.getRange("A2").getNextDataCell(SpreadsheetApp.Direction.DOWN).getLastRow()

答案 6 :(得分:2)

对于大型电子表格,此解决方案非常快:

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();

};

答案 7 :(得分:1)

尝试构建一个函数以获取单列最后一行的整数后,此方法运行良好:

    function lastRow() {
    var spreadsheet = SpreadsheetApp.getActiveSheet();
    spreadsheet.getRange('B1').activate();
    var columnB = spreadsheet.getSelection().getNextDataRange(SpreadsheetApp.Direction.DOWN).activate();
    var numRows = columnB.getLastRow();
    var nextRow = numRows + 1; 
    }

答案 8 :(得分:0)

最佳解决方案取决于您的工作表有多少行以及数据类型。我已经对各种提议的解决方案进行了比较和基准测试。大多数仅适用于纯数据,如果数据有间隙、公式、数组公式、导入范围、本地引用、过滤器或查询函数等,则会失败。几乎总是如此。

在所有数据类型上运行得相当快的始终准确的解决方案是 Reversed for + getValues() 之一。如果您不想头疼,请使用它:

    // replace 'yourSheetName' and column 1 with your values
var tab = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('yourSheetName')
var column = tab.getRange('A:A')

// get lastFilledRow
var value = ''
const max = tab.getMaxRows()
var values = column.getValues()
values = [].concat.apply([], values)
for (row = max - 1; row > 0; row--) {
  value = values[row]
  if (value != '') { break }
}
var lastFilledRow = row + 1

如果您真的想要一个单行并且您确定您的数据没有本地引用,请使用 getNextDataCell() 解决方案,它既快速又简单

// replace 'yourSheetName' and column 'A' with your values
var tab = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('yourSheetName')
var column = tab.getRange('A' + tab.getMaxRows())

// get lastFilledRow
var lastFilledRow = column.getNextDataCell(SpreadsheetApp.Direction.UP).getA1Notation().slice(1)

如果您想查看完整的分析和基准测试结果,请转到 here

答案 9 :(得分:0)

这对我有用:

var ss = SpreadsheetApp.openById(YourSpreadsheetID);
var main_sheet = ss.getSheetByName(YourMainSheet);
main_sheet.getRange('K16').activate(); // substitute your cell from where you want to count
main_sheet.getCurrentCell().getNextDataCell(SpreadsheetApp.Direction.DOWN).activate();
var last_row_submissions = main_sheet.getCurrentCell().getRowIndex();

答案 10 :(得分:0)

我意识到这是一个很旧的线程,但这是搜索此问题时的第一批结果。

对此有一个简单的解决方案,afaik一直可用...这也是在VBA中完成相同任务的“ 推荐”方式。

var lastCell = mySheet.getRange(mySheet.getLastRow(),1).getNextDataCell(
  SpreadsheetApp.Direction.UP
);

这将返回您在getRange(row,column)中指定的列中的最后一个完整单元格,如果要使用第一个空行,请记住在此添加1。

答案 11 :(得分:0)

从Mogsdad解决方案进行更新,

var searchTerm = //user input;

var countSearch = searchTerm.Split().Count(); //splits the search and count how many

var query = tables.AsQueryable();

if (countSearch == 1) // searchTerm will check any rows
{
    query = query.Where(a => 
                             searchTerm.Contains(a.Color) || 
                             searchTerm.Contains(a.Animal) || 
                             searchTerm.Contains(a.CarBrand));
            }
else if (countSearch == 2) //searchTerm will check at least two combinations on rows
{
    query  = query.Where(a => (searchTerm.Contains(a.Color) && searchTerm.Contains(a.Animal)) 
                           || (searchTerm.Contains(a.Color) && searchTerm.Contains(a.CarBrand)) 
                           || (searchTerm.Contains(a.Animal) && searchTerm.Contains(a.CarBrand)));
}
else if (countSearch == 3) //searchTern will check all rows
{
    query = query.Where(a => 
                             searchTerm.Contains(a.Color) && 
                             searchTerm.Contains(a.Animal) && 
                             searchTerm.Contains(a.CarBrand));
}

var results = query.ToList();

答案 12 :(得分:0)

我用过getDataRegion

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

请注意,这取决于数据是连续的(根据OP的请求)。

答案 13 :(得分:0)

我尝试编写以下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();
  } 
}

答案 14 :(得分:0)

我希望发布最新答案永远不会太晚。这是我的“查找最后一个单元格”的摘要。我主要对速度感兴趣。在使用大约150,000行的数据库上,此功能(平均)需要0.087秒的时间来找到解决方案,而@Mogsdad优雅的JS解决方案在上面的同一数据上要(平均)0.53秒。在调用函数之前,两个数组都已预加载。它利用递归进行二进制搜索。对于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.
 */

答案 15 :(得分:0)

我个人也遇到类似的问题,并且遇到了类似的问题:

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变量中的位置。它的优点是可以让您拥有不连续的列,并且仍然知道最后一行(假设您要遍历整个列)。

答案 16 :(得分:0)

var Direction=SpreadsheetApp.Direction;
var aLast =ss.getRange("A"+(ss.getLastRow()+1)).getNextDataCell(Direction.UP).getRow();

答案 17 :(得分:0)

这可能是另一种绕过拉斯特罗的方式。 您可能需要使用代码来满足您的需求

self.assertTrue(Model.objects.filter(**model_criteria).exists())

答案 18 :(得分:0)

获取列数或最后一列的索引:

var numColumns = sheet.getLastColumn()

获取行数或最后一行的索引:

var numRows = sheet.getLastRow()

,其中

var sheet = SpreadsheetApp.getActiveSheet()

答案 19 :(得分:-1)

我使用getDataRange()后跟getNumRows()。第一个功能

  

返回与数据存在的维度相对应的范围

和第二个功能

  

返回此范围内的行数。

var ss = SpreadsheetApp.getActiveSpreadsheet();
var ws = ss.getActiveSheet();
var lastRow = ws.getDataRange().getNumRows();

P.S我希望这适用于所有情况。

答案 20 :(得分:-1)

这是解决这个问题的另一种方法。它使用while循环,但考虑了行之间的空隙。

function getLastRow (column) {
  var iLastRow = ss.getActiveSheet().getMaxRows();
  var aValues = ss.getActiveSheet().getRange(column + ":" + column).getValues();
  var row = "";
  while(row == ""){
    row = aValues[iLastRow-1];
    iLastRow--;
  }
  return iLastRow;
}

答案 21 :(得分:-1)

我重写了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;
    }
  }
}