【问题标题】:Google sheets array formula running balance stratified by category column and sorted by date column谷歌表格数组公式运行余额按类别列分层并按日期列排序
【发布时间】:2021-04-12 02:44:56
【问题描述】:

我正在尝试找出一个数组公式来计算另一列中列出的类别中的流动余额。

这是一个示例表供参考 https://docs.google.com/spreadsheets/d/1kmitZF6YtARAi2EB0NggbIhKgsb7tLCknsKBTEKycrw/edit?usp=sharing

要求是:

  • Amount 列上计算运行余额
  • 应根据Category 列计算运行余额。 IE。 A 类下的金额应仅计入 A 的流动余额
  • 应根据按升序排列的Date 列的值计算运行余额。即使条目可能出现在未排序的工作表中。

任何帮助将不胜感激!

【问题讨论】:

  • 我不确定这种运行平衡应该是什么样子(我不是英语母语人士)。能否请您使用标准公式来举例说明。
  • 您的意思是流动余额应该只增加 C 列中的金额,忽略日期,这意味着它总是在增加?这肯定比你想考虑日期更容易。根据您当前的数据,您能否通过在 D 列中显示您期望的值来澄清一下?
  • 我添加了一个期望值列来说明。基本上,如果我要在 python 中执行此操作,我将首先按日期排序,然后按类别分组,并在每个组内进行运行平衡。然后将这些值映射回原始位置。
  • 另一种选择可能是使用数组公式+脚本。但我没有写这些的经验。
  • 我发现了这个几乎相同的问题:webapps.stackexchange.com/questions/87492/… 最好的答案是使用脚本或非数组复制功能。两者都有效,但向下复制功能似乎要好得多。一个运行速度很快的函数将是理想的,但这是迄今为止发现的最好的。

标签: google-sheets array-formulas cumulative-sum balance


【解决方案1】:

最短路径

使用SUMIFS 函数根据多个条件获取范围的总和。在您的情况下,您有两个:

  • 根据类别计算
  • 根据日期计算

结果:cell = sumifs(C$2:C,B$2:B,"="&B2,A$2:A,"<="&A2)

语法解释

SUMIFS(sum_range, criteria_range1, criterion1, [criteria_range2, criterion2, ...])

  • sum_range - 要求和的范围。

  • criteria_range1 - 对照criteria1检查的范围。

  • criterion1 - 应用于 criteria_range1 的模式或测试。

  • criteria_range2,criteria2, ... - [ 可选 ] - 要检查的其他范围和条件。

编辑

如果您需要自动填充新行,您可以将Spreadsheet Service 用于Google Apps ScriptSimple Triggers

有一个名为onEdit(e) 的触发器会在用户更改电子表格中任何单元格的值时自动运行。

您可以使用以下代码在每次更改值时更新Running balance 列。

function onEdit(e) {
  var sh = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet()
  var last_row = sh.getLastRow()
  console.log(last_row)
  var formula = '=sumifs(C2:C,B2:B,B2,A2:A,"<="&A2)'
  sh.getRange('D2:D'+last_row).setFormula(formula)
}

但是,此代码会更新整个列,覆盖旧条目的公式。如果您只想更新新条目以获得更高效的代码,可以使用以下代码。

function onEdit(e) {
  var sh = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet()
  var last_row = sh.getLastRow()
  var last_formula_row = sh.getRange('D1:D').getValues().filter(String).length
  var formula = '=sumifs(C$2:C,B$2:B,B' + last_formula_row + ',A$2:A,"<="&A'+ last_formula_row + ')'
  sh.getRange('D'+last_formula_row+':D'+last_row).setFormula(formula)
}

我附上你们两个,因为如果没有第一个,第二个可能很难理解。

参考

  • SUMIFS:根据多个条件返回范围的总和。
  • Spreadsheet Service:允许脚本创建、访问和修改 Google 表格文件。
  • Google Apps Script:由 Google 开发的脚本平台,用于在 Google Workspace 平台中开发轻量级应用程序
  • Simple Triggers:当某个事件发生时自动运行一个函数
  • onEdit(e) 当用户更改电子表格中任何单元格的值时自动运行的触发器

【讨论】:

  • 是否可以调整它以使用 ArrayForumula?
  • 我认为不可能将其调整为使用 ArrayFormula,但是我用一种解决方法编辑了我的答案,我希望它可以帮助你@Pierce
【解决方案2】:

此方法最多可用于大约 3000 行。不仅如此,我还可以链接到另一个解决方案。将空行保持在最低限度,因为工作表越长,速度就越慢。

=ARRAYFORMULA(ARRAY_CONSTRAIN(MMULT((ROW(B2:B)>=TRANSPOSE(ROW(B2:B)))*(B2:B=TRANSPOSE(B2:B)),N(C2:C)),COUNTA(B2:B),1))

【讨论】:

  • 有没有办法让它适应更多的行?我有大约 12,000 个并且还在增加。
  • 为了计算的目的,它是否也按日期排序?
【解决方案3】:

慢而短:

=INDEX(IF(A2:A="",,MMULT(1*TRANSPOSE(IF((TRANSPOSE(ROW(B2:B))>=
 ROW(B2:B))*(B2:B=TRANSPOSE(B2:B)), C2:C, 0)), ROW(A2:A)^0)))


快速和高级:

=INDEX(MMULT(1*TRANSPOSE(IF((TRANSPOSE(ROW(
 INDIRECT("B2:B"&MAX(ROW(B2:B)*(B2:B<>"")))))>=ROW(
 INDIRECT("B2:B"&MAX(ROW(B2:B)*(B2:B<>"")))))*(
 INDIRECT("B2:B"&MAX(ROW(B2:B)*(B2:B<>"")))=TRANSPOSE(
 INDIRECT("B2:B"&MAX(ROW(B2:B)*(B2:B<>""))))), 
 INDIRECT("C2:C"&MAX(ROW(B2:B)*(B2:B<>""))), 0)), ROW(
 INDIRECT("B2:B"&MAX(ROW(B2:B)*(B2:B<>""))))^0))


更新:按日期排序:

=INDEX(IF(A2:A="",,IFNA(VLOOKUP(A2:A&B2:B, {
 INDEX(SORT({A2:A&B2:B, A2:A}, 2, 1),,1), 
 MMULT(1*TRANSPOSE(IF((TRANSPOSE(ROW(B2:B))>=
 ROW(B2:B))*(INDEX(SORT({B2:B, A2:A}, 2, 1),,1)=
 TRANSPOSE(INDEX(SORT({B2:B, A2:A}, 2, 1),,1))), 
 INDEX(SORT({C2:C, A2:A}, 2, 1),,1), 0)), 
 ROW(B2:B)^0)}, 2, 0))))

【讨论】:

  • 快到了。但是在计算余额之前是否按日期列排序?
  • 太棒了!还有一个不合理的要求:) 我有大约 50K 行。这似乎在大约 6K 之后下降。你知道我们有什么办法可以解决这个问题吗?
猜你喜欢
  • 1970-01-01
  • 2011-03-13
  • 1970-01-01
  • 1970-01-01
  • 2017-07-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-20
相关资源
最近更新 更多