ArrayFormula 破坏了 getLastRow() 函数。可能的解决方法?

ArrayFormula is breaking the getLastRow() funtion. Possible workarounds?

在我的 spreadsheet 中,我有一个 运行ning 脚本,它使用 getLastRow() 函数作为其逻辑的重要部分。

自从我在其中一个专栏中应用了数组公式后,getLastRow() 函数就无法正常工作。似乎数组公式 "applying" 一直到 sheet 的底部,即使其他列中没有其他值,因此 getLastRow() 返回最后一行有一个数组公式,而不是实际的非空行。

编写一个检查哪些单元格为空的慢速函数对我来说不是一个选项,因为脚本会 运行 超时运行ning(它有数以万计的行)。

有人对解决方法有任何建议吗?

这是 ARRAYFORMULA

=ArrayFormula(IF(A2:A="",,WEEKNUM(A2:A, 2)))

问题:

  • ARRAYFORMULA(IF(A:A="",...))
  • 的传统用法在所有可用行中添加了不受欢迎的空字符串

解决方案:

  • 正确使用 ARRAYFORMULAINDEX/COUNTA(以确定需要的最后一行)确保公式只填充到需要的行而不是伪装

  • INDEX/COUNTA: INDEX returns 一个值和一个单元格引用。 A2:INDEX(A2:A,COUNTA(A2:A)) => If COUNTA(...) returns 10 => A2:INDEX(A2:A,10) => A2:A11 是提供给 weeknum

    的最终参考
  • 假设您的数据之间没有空格,

    =ARRAYFORMULA(WEEKNUM(A2:INDEX(A2:A,COUNTA(A2:A)),2))
    
  • 另一种选择是使用ARRAY_CONSTRAIN/COUNTA:

    =ARRAY_CONSTRAIN(ARRAYFORMULA(WEEKNUM(A2:A, 2)),COUNTA(A2:A))
    
  • COUNTA 的用法假定中间没有空白单元格。如果有,您可能需要手动添加偏移量。如果有两个空白单元格,请将 2 添加到 COUNTA

    A2:INDEX(A2:A,COUNTA(A2:A)+2)
    

除非 Google 进行内置优化,否则 INDEX/COUNTA 优于 ARRAY_CONSTRAIN


INDEX/COUNTA手动修复那些数组公式可能很难,所以我做了一个脚本。这只是概念和 alpha 质量的证明。因此,请在电子表格的副本中而不是在原始文件中对其进行测试。话虽如此,我相信它可以毫无问题地处理大多数常见情况。

/**
 * @see 
 */
function fixArrayFormulas_so46884012() {
  const ss = SpreadsheetApp.getActive()/*.getSheetByName('Sheet1')*/,
    map = new Map([
      [
        // Normalize first part of range
        /* A:F */ String.raw`([a-z]+):([a-z]+)`,
        /* A1:F*/ String.raw`:`,
      ],
      [
        // Convert any previous index/counta to normal ranges
        /* A1:INDEX(F:F,COUNTA(F:F)) */ String.raw`([a-z]+\d+):INDEX\(([a-z]+)\d*:\w+,COUNTA\(\w+:\w+\)\)`,
        /*A1:F*/ String.raw`:`,
      ],
      [
        // Convert open ended ranges to  index/counta ranges
        /*A1:F*/ String.raw`([a-z]+\d+:)([a-z]+)`,
        /* A1:INDEX(F:F,COUNTA(F:F)) */ `INDEX(:,COUNTA(:))`,
      ],
    ]);
  map.forEach((v, k) =>
    ss
      .createTextFinder(k)
      .matchFormulaText(true)
      .useRegularExpression(true)
      .replaceAllWith(v)
  );
}

另一种解决方案是暂时删除数组公式

sheet.getRange("location of array formula").setValue('');

然后计算最后一行

var lastRow = sheet.getLastRow();

然后替换数组公式

sheet.getRange("location of array formula").setFormula('the formula');

这是一个函数,您可以使用它来确定 Sheet 值的 "true" lastRowlastColumn 值。它将处理杂乱的 ArrayFormula() 和合并的单元格。

function getSheetBoundaries2(sheet) {
  var dim = { lastColumn: 1, lastRow: 1 };
  sheet.getDataRange().getMergedRanges()
    .forEach(function (e) {
      var lastColumn = e.getLastColumn();
      var lastRow = e.getLastRow();
      if (lastColumn > dim.lastColumn) dim.lastColumn = lastColumn;
      if (lastRow > dim.lastRow) dim.lastRow = lastRow;
    });
  var rowCount = sheet.getMaxRows();
  var columnCount = sheet.getMaxColumns();
  var dataRange = sheet.getRange(1, 1, rowCount, columnCount).getValues();
  for (var rowIndex = rowCount; rowIndex > 0; rowIndex -= 1) {
    var row = dataRange[rowIndex - 1];
    if (row.join('').length > 0) {
      for (var columnIndex = columnCount; columnIndex > dim.lastColumn; columnIndex -= 1) {
        if (("" + row[columnIndex - 1]).length > 0) dim.lastColumn = columnIndex;
      }
      if (dim.lastRow < rowIndex) dim.lastRow = rowIndex;
    }
  }
  return dim;
}