Search code examples
google-apps-scriptgoogle-sheetsgoogle-sheets-formula

How to iterate each cell of a range, NOT only the values, keeping the original index (row and column)?


Imagine we have the following Sheet:

A B C D E F
1 John Juan Pepe
2 Y N Y

Then we want to iterate the row 1:

var sheet = SpreadsheetApp.getActiveSheet();

var peopleNamesRangeWithEmptyCells = sheet.getRange('A1:F1'); // ← Here are the name of the people like John, Juan...
var peopleNamesRange = [];
peopleNamesRangeWithEmptyCells.forEach(function (cell) {
   if (cell.value() != "") {
     doSomethingOnThatColumn(cell.value(), cell.getColumn());
   }
});

But it seems I cannot iterate a range with foreach as I get the error: TypeError: peopleNamesRangeWithEmptyCells.forEach is not a function

I know the common way to go for it is using getValues():

var peopleNamesRangeWithEmptyCells = sheet.getRange('A1:F1').getValues(); // ← Here are the name of the people like John, Juan...

But then I would loose the original row and column, so I could not do something like calling a function with the column as param:

doSomethingOnThatColumn(cell.value(), cell.getColumn());

It seems a basic question, but I'm struggling: How to iterate a range and not only its values?


Solution

  • getValues() does NOT include the position of the value on the sheet as it's just an 2D array containing the values of the given range.

    A way to go would be to create the array containing the whole sheet (I got the idea from here):

      var sheet = SpreadsheetApp.getActiveSheet();
      var rangeData = sheet.getDataRange();
      var lastColumn = rangeData.getLastColumn(); 
      var lastRow = rangeData.getLastRow();
      var searchRange = sheet.getRange(1, 1, lastRow, lastColumn);
      var rangeValues = searchRange.getValues();
    

    So then we can iterate the 2D array of values, and because it contains the whole sheet, the position of a value at the 2 array of values is the same than the sheet... With an important detail: the array start by [0][0] whereas the sheet starts by (1)(A):

      for ( i = 0; i < lastColumn - 1; i++){
        for ( j = 0 ; j < lastRow - 1; j++){
          
          currentColumnInOriginalSheet = i+1;
          currentValueAtThisForLoop = rangeValues[j][i];          
          doSomethingOnThatColumn(currentColumnInOriginalSheet, currentValueAtThisForLoop);
    
        };
      };
    

    If we don't want to include the whole sheet on the 2D array of values, then we can use a variable (normally called offset) to indicate how many positions we have to add to calculate the position in the original sheet.

    So if we want to iterate the values from the column D to column F, we create a variable named offset with the number of columns from A to D (4 positions):

      var columnOffset = 4;
      var searchRange = sheet.getRange(1, columnOffset, lastRow, lastColumn);
    
      for ( i = columnOffset; i < lastColumn - 1; i++){
        for ( j = 0 ; j < lastRow - 1; j++){
          
          currentColumnInOriginalSheet = i+1;
          currentValueAtThisForLoop = rangeValues[j][i-columnOffset];          
          doSomethingOnThatColumn(currentColumnInOriginalSheet, currentValueAtThisForLoop);
    
        };
      };