Google App Script:从范围选择中删除空白行以进行排序

Posted

技术标签:

【中文标题】Google App Script:从范围选择中删除空白行以进行排序【英文标题】:Google App Script: Remove blank rows from range selection for sorting 【发布时间】:2020-07-16 03:37:41 【问题描述】:

我想在“总计”列中计算一个数字时进行实时排序,该列是基于用户输入的其他单元格的总和。排序应该是降序的,我确实使用以下方法实现了这个功能:

function onEdit(event)
  var sheet = event.source.getActiveSheet();
  var range = sheet.getDataRange();
  var columnToSortBy = 6;
  range.sort(  column : columnToSortBy, ascending: false  );


它简短而甜蜜,但是总列中包含以下公式的空单元格,如果总和结果为零,则将其空白,否则打印结果:

=IF(SUM(C2:E2)=0,"",SUM(C2:E2))

它会导致这些带有不可见公式的行包含在范围选择中,并且在降序排序时,由于某种原因,它们会被顶上去。我希望这些空白行在排序之前排序到底部,或者在理想情况下从范围本身中删除(不删除它们以及它们从工作表中包含的公式)。

或者也许是一些更好的方法,它不需要我将公式拖过一整列大部分为空行的列。随着新条目的出现,我目前已采取手动一一添加公式的方式,但我宁愿避免这种情况。

编辑:根据要求在下面找到工作表的屏幕截图。如下图,第 6 列的总分需要按降序排列,赢家排在最前面。这应该有一个纵向运行的预先粘贴的公式,它总结了每个参与者的前面的列。

它前面的列(等级积分)是通过将“等级”列乘以 10 来自动计算得出的最终分数。可以消除此列,并且一旦离开,所有内容都会发生变化,但是保持实际获得的分数的视觉效果很好。用户输入在 3 个白色列中输入。

【问题讨论】:

公式的用途是什么?你能分享一张显示其用途的表格截图吗?如果实际的 c5:e5 为 1,-1,0 或为空白,则删除 0 的目的是什么,ifc5:e5 为空白且底部未使用(它只是底部的一堆空行)?跨度> @TheMaster 用截图更新了问题。 Tanaike 的答案大部分都在那里,但公式被粘贴为值,这对于作为所达到等级点视觉效果的第 5 列是有问题的。 【参考方案1】: 您希望按“F”列的降序对工作表进行排序。 您希望通过忽略“F”列中的空单元格来对工作表进行排序。 您想将空行移到行的底部。 您不想更改“F”列中的公式。 您希望使用 Google Apps 脚本实现此目的。

如果我的理解是正确的,那么这个答案呢?

问题和解决方法:

现阶段,当空单元格分散在“F”列时,我认为不能直接使用Class Range的“排序”内置方法。空单元格像您的问题一样移动到行的顶部。所以在这个答案中,我想建议针对这种情况使用 javascript 的 sort 方法。

修改脚本:

要运行此功能,请编辑一个单元格。

function onEdit(event)
  const columnToSortBy = 6; // Column "F"
  const headerRow = 1; // 1st header is the header row.
  
  const sheet = event.source.getActiveSheet();
  const values = sheet.getRange(1 + headerRow, 1, sheet.getLastRow() - headerRow, sheet.getLastColumn())
    .getValues()
    .sort((a, b) => a[columnToSortBy - 1] > b[columnToSortBy - 1] ? -1 : 1)
    .reduce((o, e) => 
      o.a.push(e.splice(0, columnToSortBy - 1));
      e.splice(0, 1);
      if (e.length > 0) o.b.push(e);
      return o;
    , a: [], b: []);
  sheet.getRange(1 + headerRow, 1, values.a.length, values.a[0].length).setValues(values.a);
  if (values.b.length > 0) 
    sheet.getRange(1 + headerRow, columnToSortBy + 1, values.b.length, values.b[0].length).setValues(values.b);
  

在这个示例脚本中,它假设标题行是第一行。如果您的情况没有使用标题行,请修改为const headerRow = 0;。 根据您的问题,我无法理解除“F”列之外的其他列。因此,在此示例脚本中,数据范围中除“F”列之外的所有列都被替换为排序。请注意这一点。

注意:

请使用此示例脚本启用 V8。

参考资料:

sort(sortSpecObj) sort()

补充:

您希望按“F”列的降序对工作表进行排序。 您希望通过忽略“F”列中的空单元格来对工作表进行排序。 您想将空行移到行的底部。 在您的情况下,“A”到“F”列中有值。 公式不仅包含在“F”列中,还包含在其他列中。 您不想更改公式。 您希望使用 Google Apps 脚本实现此目的。

从您的回复和更新的问题中,我可以理解如上。试试这个示例脚本:

示例脚本:

function onEdit(event)
  const columnToSortBy = 6; // Column "F"
  const headerRow = 1; // 1st header is the header row.

  const sheet = event.source.getActiveSheet();
  const range = sheet.getRange(1 + headerRow, 1, sheet.getLastRow() - headerRow, 6);
  const formulas = range.getFormulas();
  const values = range.getValues().sort((a, b) => a[columnToSortBy - 1] > b[columnToSortBy - 1] ? -1 : 1);
  range.setValues(values.map((r, i) => r.map((c, j) => formulas[i][j] || c)));

【讨论】:

您好 Tanaike,您的解决方案似乎确实适用于内部公式作为值粘贴的警告。有没有办法让排序后的内容保持原样(比如公式保留为公式?) @Luponius 感谢您的回复。我带来的不便表示歉意。从您的回复和更新的问题中,我又添加了一个示例脚本。你能确认一下吗?如果我再次误解了您的情况和目标,我深表歉意。 就是这样!您能否解释一下设置值行以及其中发生了什么?将其标记为已回答,因为这正是我所需要的,只是不太确定最终设置值命令发生了什么 @Luponius 感谢您的回复。我很高兴你的问题得到了解决。关于最后一行的脚本,这里循环使用valuesformulas这两个数组。当单元格有公式时,公式被放入相同的单元格值。这样,该值将替换为公式。 Ref如果这个解释没有用,我很抱歉。【参考方案2】:

解决这个问题的一个更简单的方法是改变

=IF(SUM(C2:E2)=0,"",SUM(C2:E2))

=IF(SUM(C2:E2)=0,,SUM(C2:E2))

当总和为零时变为空白的单元格将被视为真正的空单元格,它们将被排除在排序之外,因此只有具有内容的单元格才会显示在工作表的顶部。

为什么您的原始公式不起作用是因为使用 "" 实际上会导致单元格包含内容,因此不再将其视为空白单元格。您可以通过在另一个单元格中输入ISBLANK(F1) 来测试这一点,并检查两个公式之间的差异。

【讨论】:

以上是关于Google App Script:从范围选择中删除空白行以进行排序的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Google App Script 从 Youtube 搜索中创建 RSS 提要?

在Google-App-Script for Google云端硬盘中如果标题包含某个字词,如何将某些文件从root移动到某个文件夹?

如何从 Google App Script 中的文件运行保存的 Big Query 脚本? [关闭]

Google App Script Web App GET 和 POST 请求被 CORS 策略阻止

如何向 Google Apps Script Web App 发送有效的 HTTP 请求?

来自 Google App Script 的 JDBC/mysql 连接字符串问题