使用 ARRAYFORMULA 计算 运行 应付账款总额(替代 INDIRECT)

Using ARRAYFORMULA to Calculate Running Total of Payables (Alternative to INDIRECT)

我使用 Google Spreadsheet 来跟踪每个供应商的应付账款。 Spreadsheet 中每个供应商有一个 sheet。简化的 sheet 看起来像这样:

当我收到新发票时,会在 Credit 列中输入金额,当我发放付款时,会在 Debit 列中输入金额。我在 AC Payable 列中跟踪 运行 总数。我通过在 AC Payable 列的每个单元格中使用一个公式来实现这一点(下面的示例来自单元格 E4):

=IF(
  ISNUMBER(INDIRECT(ADDRESS(ROW()-1,COLUMN()))),
  INDIRECT(ADDRESS(ROW()-1,COLUMN()))+C4-D4,
  C4-D4
)

逻辑很简单。 n 行的 运行 总计计算公式为:

AC Payable(n - 1) + Credit(n) - Debit(n)

此设置工作正常,除了我必须将公式拖到新添加的行中。有没有办法通过使用 ARRAYFORMULA?

来实现这一点

PS: 我找到了一个解决方案:

= ARRAYFORMULA(
    SUMIF(
      ROW(C3:C),
      "<="&ROW(C3:C),
      C3:C) 
    - 
    SUMIF(
      ROW(D3:D),
      "<="&ROW(D3:D),
      D3:D
    )
  )

我觉得这是一个次优的解决方案(最初的 sheet 可以追溯到 2018 年。它有很多行)解决方案,因为在每一行中,它都会计算 DebitCredit 列到当前行,然后从 Credit 列的总和中减去 Debit 列的总和。

我期待一个解决方案,它可以利用上一行中可用的 运行 总数,而不是每行重做整个计算。

最多 1581 行的解决方案:

=ARRAYFORMULA(QUERY(QUERY(MMULT(TRANSPOSE((SEQUENCE(COUNTA(A3:A)*2)<=
 SEQUENCE(1, COUNTA(A3:A)*2))*FLATTEN(INDIRECT("C3:D"&COUNTA(A3:A)+ROW(A3)-1)*{1, -1})), 
 SEQUENCE(COUNTA(A3:A)*2, 1, 1, 0)), "offset 1", ), "skipping 2", ))

技能:

  • 速度很快
  • 很聪明
  • 添加的行越多,速度越慢
  • 在 1581 行后死亡

它基于标准 MMULT Running/Cumulative Total/Sum 公式:

=ARRAYFORMULA(MMULT(TRANSPOSE((ROW(B1:B6) 
 <=TRANSPOSE(ROW(B1:B6)))*B1:B6), SIGN(B1:B6)))

但有一个修改扭曲,因为你总共有 2 列

而不是 ROW(B1:B6) 我们使用实际数据的计数序列乘以 2(因为你有 2 列):

SEQUENCE(COUNTA(A3:A)*2)

而不是 TRANSPOSE(ROW(B1:B6)) 我们再次使用:

SEQUENCE(1, COUNTA(A3:A)*2)

这些作品的组合:

=ARRAYFORMULA(TRANSPOSE((SEQUENCE(COUNTA(A3:A)*2)<=SEQUENCE(1, COUNTA(A3:A)*2))))

将生成如下矩阵:

这就是它死于大量行的原因,因为虽然您可能认为如果两列中只有 1500 行,那么公式将仅适用于 1500*2=3000 个虚拟单元格,但实际上MMULT 公式处理 (1500*2)*(1500*2)=9000000 个虚拟单元格。不过,值得注意的是,如果小规模部署,这个 MMULT fx 还是很棒的。

接下来,我们使用

而不是 *B1:B6
*FLATTEN(INDIRECT("C3:D"&COUNTA(A3:A)+ROW(A3)-1)*{1, -1}))

例如。对于 INDIRECT,我们只采用 C3:D 的“有效”范围,在您的示例中 sheet 只是 C3:D5,我们将 C 列乘以 1,将 D 列乘以 -1 来模拟减法,然后我们将两列展平为一列。 +ROW(A3)-1 部分只是一个偏移量,因为您从第 3

行开始

并且标准 RT fx 的最后一部分 - SIGN(B1:B6) 被替换为一栏全是:

SEQUENCE(COUNTA(A3:A)*2, 1, 1, 0)

然后我们将内部 QUERY 的输出偏移 1,因为我们对减法后的总计感兴趣,最后我们使用 skipping 2 这意味着我们过滤掉每个第二个值 - 同样,我们对总计感兴趣减去 D 列后。


超过1581行的解决方法:

=ARRAYFORMULA(
 SUMIF(SEQUENCE(COUNTA(A3:A)), "<="&SEQUENCE(COUNTA(A3:A)), INDIRECT("C3:C"&COUNTA(A3:A)))-
 SUMIF(SEQUENCE(COUNTA(A3:A)), "<="&SEQUENCE(COUNTA(A3:A)), INDIRECT("D3:D"&COUNTA(A3:A))))

技能:

  • 支持更多行
  • 看起来不那么聪明
  • 遗憾的是 SUMIF 的第三个参数总是需要一个范围
  • 行数越多越慢
  • 喂10000行它会生病
  • 它可能会杀死你的 sheet 超过 11000 行

这里是Ben Collins' running total formula

的修改
=ARRAYFORMULA(
  IF(ISBLANK(A2:A),,
   MMULT(TRANSPOSE((ROW(C2:C)<=TRANSPOSE(ROW(C2:C)))*C2:C),SIGN(C2:C))-
   MMULT(TRANSPOSE((ROW(D2:D)<=TRANSPOSE(ROW(D2:D)))*D2:D),SIGN(D2:D))))

MMULT 的另一种选择:

=INDEX(QUERY(FLATTEN(QUERY(QUERY(TRANSPOSE(QUERY(QUERY(TRANSPOSE(
 (SEQUENCE(COUNTA(A3:A)*2)<=SEQUENCE(1, COUNTA(A3:A)*2))*
 FLATTEN(INDIRECT("C3:D"&COUNTA(A3:A)+ROW(A3)-1)*{1, -1})), 
 "offset 1", ), "skipping 2", )), "select "&QUERY( 
 "sum(Col"&SEQUENCE(COUNTA(A3:A))&"),",, 9^9)&"' '"), 
 "offset 1", )), "where Col1 is not null", ))

但同样,LTE (<=) 1000 万个单元格的限制不会让您在您的案例中使用超过 1581 行或在标准累积和案例中使用 3162 行

(1581 rows * 2 columns) raised on 2nd power < 10 million cells

(1581*2)^2 = 9998244