Bestimmen der letzten Zeile in einer einzelnen Spalte


71

Ich habe ein Blatt mit Daten in Spalten Adurch H.

Ich muss die letzte Zeile in der Spalte bestimmen A, die Daten enthält (alles ist zusammenhängend - keine Lücken in den Daten / Zeilen).

Es gibt auch Daten in den anderen Spalten, die mehr Datenzeilen als Spalten enthalten A, sodass ich nur die Spalte isolieren muss A. (Und / oder nur ein Bereich innerhalb von Spalte A).

Ich kann dies auf Tabellenkalkulationsebene mit tun

=COUNTA(A2:A100)

Bei all meinen Recherchen nach einer Google Apps Script-Lösung scheine ich jedoch nur Anforderungen zu finden, um mehrere Funktionen auszuführen, die Dutzende von Codezeilen umfassen - einschließlich vieler i++Dinge ... Was ich durch direktes Versetzen weniger komplex machen könnte A1.

Gibt es möglicherweise eine spaltenspezifische Möglichkeit, diese Methode zu ändern?

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

Wenn ein komplizierter Prozess erforderlich ist, dann sei es so. Aber ich finde es schwierig, mir eine einfachere Lösung vorzustellen (und noch schwieriger zu finden!).

Möchte mich jemand aufklären (oder meine Blase platzen lassen)?

Antworten:


168

Wie wäre es mit einem JavaScript-Trick?

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

Ich habe diese Idee aus dieser Antwort entlehnt . Die Array.filter()Methode arbeitet mit dem AvalsArray, das alle Zellen in Spalte A enthält. Durch Filtern nach dem Konstruktor einer nativen Funktion erhalten wir nur Nicht-Null-Elemente zurück.

Dies funktioniert nur für eine einzelne Spalte. Wenn der Bereich mehrere Spalten enthält, enthält das Ergebnis von filter()Zellen aus allen Spalten und liegt somit außerhalb der aufgefüllten Dimensionen des Bereichs.


9
Sehr schlau. Ich freue mich auf den Tag, an dem ich Javascript gut genug verstehe, um so kreativ zu denken. Alles zu gegebener Zeit, nehme ich an. In der Zwischenzeit habe ich es jedoch genossen zu sehen, wie Sie denken. Und ein großes Lob an Sie, dass Sie die Inspiration für Ihre Lösung zitiert haben. Nobel. Nochmals vielen Dank.
5.4x4

1
Für erfahrene Codierer ist es mit ziemlicher Sicherheit offensichtlich, dass der Bereich nicht mehr als eine einzelne Spalte umfassen kann. Dies war etwas, das ich nicht ganz verstanden habe, aber Mogsdad wies in einem Kommentar (der gelöscht wurde) darauf hin, dass es nicht mehr als eine einzelne Spalte umfassen kann. Auch hier möchte ich dies nur für diejenigen einfügen, die auf meiner Erfahrungsebene sind und immer noch Probleme haben, einige Konzepte zu verstehen. Danke, Mogsdad.
Soundfx4

4
@ 5th4x4 Klärende Frage eines Javascript-Neulings: Würde das nicht die Anzahl der Zellen in einer Zeile zurückgeben, die nicht null waren, nicht unbedingt die Nummer der Zeilennummer der letzten Zelle mit Inhalt, wenn es eine Lücke in den obigen Zellen gab irgendwo? So etwas wie diese while-Schleife könnte verwendet werden, um nur die Nullelemente vom Ende des Arrays abzuschneiden.
Scotosaurus

1
@ Scotosaurus Das stimmt. Die Frage befasst sich jedoch speziell mit der Tatsache, dass die Daten keine leeren Lücken aufweisen: "Es ist alles zusammenhängend - keine Lücken in den Daten / Zeilen", daher ist die Antwort korrekt, funktioniert jedoch nicht bei Daten mit Lücken.
dnlmzw

1
Ich kann das nicht verstehen, ist ein String in der var Alast = Avals.filter(String).length;Variablen?
Avazbek Ismanov

13

Obwohl es keine einfache Formel gibt, die ich mir vorstellen kann, sind nicht Dutzende von Codezeilen erforderlich, um die letzte Zeile in Spalte A herauszufinden. Probieren Sie diese einfache Funktion aus. Verwenden Sie es in einer Zelle wie gewohnt, wenn Sie eine andere Funktion verwenden würden=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 ;
    }
  }
}

Das Obige gibt die letzte Zeile des gesamten Arbeitsblatts zurück, nicht Spalte A. Ich benötige NUR die letzte Zeile von Spalte A in Form einer Variablen zur Verwendung im Skript selbst. Da es dafür keine magische Pille gibt, werde ich mich wahrscheinlich von A1 zurückziehen, bis ich auf (leeren) Paydirt drücke. Danke trotzdem.
5.4x4

1
Entschuldigung, es war ein kleiner Fehler von meinem Ende. Bitte beachten Sie das korrigierte Skript.
Srik

9

Dadurch wird die letzte Zeile in einem Blatt basierend auf Spalte A angezeigt.

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

Dies behebt die teilweise korrekte Antwort von @ mrityunjay-pandey.

Um diese Antwort zu erweitern und die letzte Zeile und Spalte zu erhalten, können wir Folgendes verwenden:

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
nett! Ich mag diese zusätzlichen Funktionen
Unreality

1
Warum ist die Antwort von @ mrityunjay-pandey Ihrer Meinung nach teilweise korrekt?
TheMaster

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

Laut Dokumentation ist getNextDataCell ähnlich, um in den angegebenen Bereich zu wechseln und Strg (Befehl) + die Pfeiltaste zu drücken. Das funktioniert also, weil es zur letzten möglichen Zeile geht, eine (Pfeil nach unten) und dann Strg + NACH OBEN hinzufügt, sodass es definitiv die letzte Zeile mit etwas Inhalt erhält. Das einzige, was verbessert werden könnte, ist zu überprüfen, ob die letzte Zelle + 1 größer als die maximale Zelle ist, und eine spezifische Logik für diesen Fall zu erstellen.


Bitte geben Sie nicht nur die Postleitzahl ein, sondern fügen Sie auch eine Erklärung hinzu.
Bestimmte Leistung

1
Laut Dokumentation, getNextDataCell ist es ähnlich, in den angegebenen Bereich zu gehen und Strg (Befehl) + die Pfeiltaste zu drücken. Das funktioniert also, weil es zur letzten möglichen Zeile geht, eine (Pfeil nach unten) und dann Strg + NACH OBEN hinzufügt, sodass es definitiv die letzte Zeile mit etwas Inhalt erhält. Das einzige, was verbessert werden könnte, ist zu überprüfen, ob die letzte Zelle + 1 größer als die maximale Zelle ist, und eine spezifische Logik für diesen Fall zu erstellen.
Lopezzvit

FEHLT, wenn getLastRow () == getMaxRows ().
Maxhugen

5

Sie können dies in umgekehrter Reihenfolge tun. Beginnen Sie mit der letzten Zeile in der Tabelle und gehen Sie nach oben, bis Sie einen Wert erhalten. Dies funktioniert in allen Fällen auch dann, wenn dazwischen einige leere Zeilen liegen. Der Code sieht wie folgt aus:

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

Ich hoffe, es ist nie zu spät, eine alternative Antwort zu veröffentlichen. Hier ist ein Ausschnitt aus meiner letzten Zelle finden. Ich interessiere mich hauptsächlich für Geschwindigkeit. In einer Datenbank, die ich mit ungefähr 150.000 Zeilen verwende, dauerte diese Funktion (durchschnittlich) 0,087 Sekunden, um eine Lösung zu finden, verglichen mit der eleganten JS-Lösung von @Mogsdad, über der (durchschnittlich) 0,53 Sekunden für dieselben Daten benötigt werden. Beide Arrays wurden vor dem Funktionsaufruf vorinstalliert. Es verwendet die Rekursion, um eine binäre Suche durchzuführen. Bei mehr als 100.000 Zeilen sollten Sie feststellen, dass nicht mehr als 15 bis 20 Sprünge erforderlich sind, um das Ergebnis zurückzugeben.

Ich habe die Log-Aufrufe belassen, damit Sie sie zuerst in der Konsole testen und ihre Funktionsweise sehen können.

/* @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
Immer noch langsamer als diese Antwort . Aber diese Antwort ist gut.
TheMaster

3

Ich habe getDataRegion verwendet

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

Beachten Sie, dass dies davon abhängt, dass die Daten zusammenhängend sind (gemäß der Anforderung des OP).


2

So ermitteln Sie die Anzahl der Spalten oder den Index der letzten Spalte:

var numColumns = sheet.getLastColumn()

So ermitteln Sie die Anzahl der Zeilen oder den Index der letzten Zeile:

var numRows = sheet.getLastRow()

wo

var sheet = SpreadsheetApp.getActiveSheet()

6
Dies betrifft das gesamte Blatt, einschließlich leerer Zellen, was nicht so klingt, wie es das OP will.
Ryantuck

2

Für sehr große Tabellen ist diese Lösung sehr schnell:

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

Nach einer Weile beim Versuch, eine Funktion zu erstellen, um eine Ganzzahl mit der letzten Zeile in einer einzelnen Spalte zu erhalten, funktionierte dies einwandfrei:

    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

Dies kann ein anderer Weg sein, um Lastrow zu umgehen. Möglicherweise müssen Sie mit dem Code herumspielen, um Ihren Anforderungen zu entsprechen

    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

persönlich hatte ich ein ähnliches Problem und ging mit so etwas:

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
}

Es sucht nach der Anzahl der Zeilen im ws und durchläuft jede Zelle in Ihrer Spalte. Wenn eine nicht leere Zelle gefunden wird, wird die Position dieser Zelle in der Variablen last_row_col aktualisiert. Es hat den Vorteil, dass Sie nicht zusammenhängende Spalten haben und trotzdem die letzte Zeile kennen (vorausgesetzt, Sie gehen die gesamte Spalte durch).


0

Ich habe versucht, 3 folgende Funktionen zu schreiben, Sie können sie für verschiedene Fälle von Ihnen testen. Dies sind die Daten, mit denen ich getestet habe:

Geben Sie hier die Bildbeschreibung ein

Die Funktionen getLastRow1 und getLastRow2 geben 0 für Spalte B zurück. Die Funktion getLastRow3 gibt 1 für Spalte B zurück

Abhängig von Ihrem Fall werden Sie sie an Ihre Bedürfnisse anpassen.

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

Update von der Mogsdad-Lösung,

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


1
Ich denke, diese Antwort würde von einer besseren Formatierung profitieren

0

Mir ist klar, dass dies ein ziemlich alter Thread ist, aber es ist eines der ersten Ergebnisse bei der Suche nach diesem Problem.

Es gibt eine einfache Lösung dafür, die afaik schon immer zur Verfügung hatte ... Dies ist auch die " empfohlene " Methode, um dieselbe Aufgabe in VBA auszuführen.

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

Dies gibt die letzte vollständige Zelle in der Spalte zurück, die Sie in getRange angegeben haben (Zeile, Spalte). Denken Sie daran, 1 hinzuzufügen, wenn Sie die erste leere Zeile verwenden möchten.


Gibt dies einen Bereich zurück? Möchten Sie nicht, dass dies als letzte Zahl zurückgegeben getLastRow()wird?
DanCue

0

Das hat bei mir funktioniert:

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

Ich habe die Funktionen getLastRow / getLastColumn umgeschrieben, um einen Zeilenindex oder Spaltenindex anzugeben.

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

Hier ist eine alternative Möglichkeit, dies zu lösen. Es verwendet eine whileSchleife, berücksichtigt jedoch leere Lücken zwischen Zeilen.

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

Warum sollten Sie in der maximalen Reihe beginnen? Beginnen Sie einfach in der letzten Zeile mit Daten (in einer beliebigen Spalte) und überprüfen Sie dann die gewünschte Spalte.
Der

-1

Ich benutze getDataRange()gefolgt von getNumRows(). Die erste Funktion

Gibt einen Bereich zurück, der den Dimensionen entspricht, in denen Daten vorhanden sind

und die zweite Funktion

Gibt die Anzahl der Zeilen in diesem Bereich zurück.

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

PS Ich hoffe das funktioniert in allen Fällen.


1
Dies ist keine Antwort auf op, da op angibt, dass möglicherweise mehr Datenzeilen in anderen Spalten vorhanden sind. getDataRangeGibt ein rechteckiges Array zurück.
Der
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.