确定单列中的最后一行


72

我有一张表格,其中数据A通过H

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

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

我可以在电子表格级别使用

=COUNTA(A2:A100)

但是,在我对Google Apps脚本解决方案的所有研究中,我似乎都发现执行包含数十行代码的多种功能的要求-包括很多 i++内容...通过直接从偏移,我可以做的更简单A1

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

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

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

有人愿意启发我(或吹泡泡)吗?

Answers:


168

如何使用JavaScript技巧?

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

我从这个答案中借鉴了这个想法。该Array.filter()方法对Avals数组进行操作,该数组包含A列中的所有单元格。通过对本机函数的构造函数进行过滤,我们仅获取非null元素。

这仅适用于单列;如果范围包含多个列,则的结果filter()将包括所有列中的单元格,因此不在该范围的填充尺寸范围内。


9
很狡猾。我期待着一天,当我对JavaScript的了解足够深,能够像那样创造性地思考时。我想是在适当的时候。但是与此同时,我很高兴看到您的想法。对于您引用解决方案的灵感表示由衷的感谢。优雅 再次感谢。
2013年

1
需要指出的是,对于经验丰富的编码人员而言,几乎可以肯定地看到的是,范围不能超过单个列。这是我不太了解的事情,但是Mogsdad在一条注释(已删除)中指出了这一点,它的跨度不能超过单个列。再次,我只想将这些内容放在我的经验水平上,但仍难以掌握一些概念。谢谢,Mogsdad。
Soundfx4 2015年

4
@ 5th4x4澄清来自javascript新手的问题:如果上述单元格中有空格,那不会返回行中非空单元格的数量,不一定返回具有内容的最后一个单元格的行号某处?因此,类似while循环之类的东西可以用来将空元素修剪掉数组的末尾。
Scotosaurus

1
@Scotosaurus是的。但是,该问题专门解决了以下事实:数据没有任何空白:“它是连续的-数据/行中没有空白”,因此答案是正确的,但不适用于有空白的数据。
dnlmzw

1
我不明白,var Alast = Avals.filter(String).length;变量中是否有String ?
阿瓦兹别克·伊斯马诺夫

13

尽管没有直截了当的公式,但我可以想到,它不需要数十行代码就能找到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 ;
    }
  }
}

上面的代码返回整个工作表的最后一行,而不是colA。我只需要在脚本本身中使用变量形式的col A的最后一行即可。既然没有为此而生的魔术药,我想我会从A1圈下来直到我击中(空)paydirt。不管怎么说,还是要谢谢你。
5th4x4

1
抱歉,这是我的一个小错误。请参阅更正的脚本。
Srik

9

假设基于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)];
}

1
真好!我喜欢那些额外的功能
Unreality

1
为什么@ mrityunjay-pandey根据您的回答部分正确?
TheMaster

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

根据文档,getNextDataCell类似于转到给定范围并按ctrl(命令)+箭头键。这样做之所以可行,是因为它转到了可能的最后一行,添加了一个(向下箭头),然后按ctrl + UP,因此它肯定会获得最后包含某些内容的行。唯一可以改进的是检查最后一个单元格+ 1是否大于最大单元格,并针对这种情况做出特定的逻辑。


请不要只发布代码-也要添加说明。
某些性能

1
根据文档,getNextDataCell类似于转到给定范围并按ctrl(命令)+箭头键。这样做之所以可行,是因为它转到了可能的最后一行,添加了一个(向下箭头),然后按ctrl + UP,因此它肯定会获得最后包含某些内容的行。唯一可以改进的是检查最后一个单元格+ 1是否大于最大单元格,并针对这种情况做出特定的逻辑。
lopezvit

如果getLastRow()== getMaxRows(),则失败。
maxhugen '20

5

您可以通过相反的方式进行操作。从电子表格的最后一行开始,一直到获得一些价值为止。即使您之间有一些空行,在所有情况下都可以使用。代码如下所示:

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

我希望发布一个替代答案永远不会太晚。这是我的“查找最后一个单元格”的摘要。我主要对速度感兴趣。在使用大约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.
 */

2
仍然比这个答案慢。但是这个答案很好。
TheMaster '20

3

我用过getDataRegion

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

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


2

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

var numColumns = sheet.getLastColumn()

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

var numRows = sheet.getLastRow()

哪里

var sheet = SpreadsheetApp.getActiveSheet()

6
这会查看整个工作表,包括空白单元格,听起来好像不是OP想要的。
ryantuck

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

};

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

0

这可能是绕过lastrow的另一种方法。您可能需要尝试使用适合自己需要的代码

    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

就个人而言,我遇到了类似的问题,并遇到了类似这样的问题:

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

我尝试编写以下3个函数,您可以针对您的不同情况对其进行测试。这是我测试过的数据:

在此处输入图片说明

函数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();
  } 
}

0

来自Mogsdad解决方案的更新,

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


1
我认为此答案将受益于更好的格式设置

0

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

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

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

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


这会返回范围吗?您不希望这个像上一个一样返回数字getLastRow()吗?
DanCue

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

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

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

为什么要从最大行开始?只需从数据的最后一行开始(在任何列中),然后检查所需的列。
tehhowch

-1

我使用的getDataRange()getNumRows()。第一项功能

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

第二个功能

返回此范围内的行数。

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

PS我希望这适用于所有情况。


1
这不是op的答案,因为op指出其他列中可能存在更多数据行。getDataRange返回一个矩形数组。
tehhowch
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.