确定单个列中的最后一行

5th*_*4x4 50 google-sheets google-apps-script

我在COLS与数据在片材A通过H.

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

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

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

=COUNTA(A2:A100)
Run Code Online (Sandbox Code Playgroud)

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

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

var aLast = ss.getDataRange().getNumRows();
Run Code Online (Sandbox Code Playgroud)

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

有人关心开导我(或弹出我的泡泡)?

Mog*_*dad 127

如何使用JavaScript技巧?

var Avals = ss.getRange("A1:A").getValues();
var Alast = Avals.filter(String).length;
Run Code Online (Sandbox Code Playgroud)

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

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

  • 非常狡猾.我期待有一天,我能够很好地理解javascript,以创造性地思考.我猜想,所有这些都应该到期.然而在此期间,我很高兴看到你的想法.并感谢您引用解决方案的灵感.优雅.再次感谢. (6认同)
  • @ 5th4x4澄清来自javascript新手的问题:不会返回一行中非空的单元格数,如果上面的单元格中存在间隙,则不一定是包含内容的最后一个单元格的行数某处?所以像这样[while循环](/sf/answers/1775327781/)可以用来修剪数组末尾的空元素. (3认同)
  • 需要指出的是,对于更有经验的编码人员来说,几乎肯定显而易见的是,该范围不能跨越超过一列。这是我不太明白的事情,但 Mogsdad 在评论(已删除)中指出了这一点,它不能跨越多个列。再说一次,我只是想把这个放在这里,供那些处于我的经验水平但仍然难以掌握某些概念的人使用。谢谢,莫格达德。 (2认同)
  • 我无法理解,“var Alast = Avals.filter(String).length;”变量中是一个字符串吗? (2认同)

Sri*_*rik 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 ;
    }
  }
}
Run Code Online (Sandbox Code Playgroud)


小智 8

var Direction=SpreadsheetApp.Direction;
var aLast =ss.getRange("A"+(ss.getLastRow()+1)).getNextDataCell(Direction.UP).getRow();
Run Code Online (Sandbox Code Playgroud)

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

  • 如果 getLastRow() == getMaxRows() 则失败。 (2认同)

小智 6

我用过getDataRegion

sheet.getRange(1, 1).getDataRegion(SpreadsheetApp.Dimension.ROWS).getLastRow()
Run Code Online (Sandbox Code Playgroud)

请注意,这依赖于连续的数据(根据 OP 的请求)。


小智 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;
}
Run Code Online (Sandbox Code Playgroud)


Al *_*hri 5

假设基于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();
  }              
}
Run Code Online (Sandbox Code Playgroud)

这可以修复@ 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)];
}
Run Code Online (Sandbox Code Playgroud)


Dee*_*789 5

我希望发布替代答案永远不会太晚。这是我查找最后一个单元格的片段。我主要对速度感兴趣。在我使用大约 150,000 行的数据库上,与上面的@Mogsdad 优雅的 JS 解决方案相比,该函数需要(平均)0.087 秒才能找到解决方案,后者在相同数据上需要(平均)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.
 */
Run Code Online (Sandbox Code Playgroud)

  • 仍然比[这个答案](/sf/answers/3603134671/)慢。但这个答案很好。 (2认同)

小智 5

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

ws.getRange("A2").getNextDataCell(SpreadsheetApp.Direction.DOWN).getLastRow()
Run Code Online (Sandbox Code Playgroud)


soM*_*rio 5

2021 年更新 - 也考虑空单元格

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

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

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

在此处输入图片说明

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

解决方案:

使用反向方法从数组末尾开始查找第一个非空值的索引

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]!='');
Run Code Online (Sandbox Code Playgroud)