我有一张包含cols A
到H
的数据的工作表。
我需要确定列A
中包含数据的最后一行(它们都是连续的 - 数据/行中没有间隙)。
其他列中的数据还有多行数据行而不是列A
,因此我只需要隔离列A
。 (和/或只是col A
内的范围)。
我可以使用
在电子表格级别执行此操作=COUNTA(A2:A100)
然而,在我对Google Apps脚本解决方案的所有研究中,我似乎发现需要执行包含数十行代码的多种功能 - 包括大量i++
内容...我能做什么通过直接从A1
抵消来减少复杂性。
是否可能采用特定于列的方法来修改此方法?
var aLast = ss.getDataRange().getNumRows();
如果需要一个复杂的过程,那就这样吧。但我觉得很难想象(甚至更难找到!)一个更简单的解决方案。
有人关心启发我(或弹出我的泡泡)吗?
答案 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)
接受的答案以及大多数答案(如果不是全部)都有一个共同的限制,对于问题的所有者(他们有连续的数据)但对于未来的读者来说可能不是这种情况。
例如,考虑这个非常简单的场景:
接受的解决方案会给出 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)
sheet.getRange(1, 1).getDataRegion(SpreadsheetApp.Dimension.ROWS).getLastRow()
请注意,这取决于数据是连续的(根据OP的请求)。
答案 13 :(得分: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();
}
}
答案 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;
}
}
}