【问题标题】:How to do a row-wise sum in an array formula in Excel?如何在Excel中的数组公式中进行逐行求和?
【发布时间】:2020-04-21 01:17:24
【问题描述】:

假设我有以下基本电子表格:

    A   B   C   D
1  -2   4   2  12
2  -1   1   0
3   0   0   0  22
4   1   1   2  12
5   2   4   6
6   3   9  12

A 列包含从 -2 到 3 的整数。

B 列具有 a 列值的平方。

C 列是 A 和 B 的行和,因此 C1 为 =SUM(A1:B1)。

D1 有 =MAX(C1:C6),这个最大值是我需要用一个公式得到的结果。

D3 是用 Ctrl+Shift+Enter 输入的 =MAX(SUM(A1:B6)),但它只会产生一个常规的总和。 D4 是 =MAX(A1:A6+B1:B6) 和 ctrl+shift+enter,这有效并给出了 12 的正确结果。

但是,D4 的问题是我需要能够处理大动态范围,而无需输入无穷无尽的总和。假设 SUM(A1:Z1000) 将是 A1:A1000+B1:B1000+....+Z1:Z1000,这不是一个合理的公式。

那么我该如何做类似 =MAX(SUM(A1:Z1000)) 的事情,这样它将 A1:Z1 到 A1000:Z1000 行相加,并给我最终的 row-wize max。

我只能使用基本 Excel,所以没有辅助列,也没有 VBA 函数。

更新 由于没有任何成功的答案,我不得不假设当前的 Excel 版本是不可能的。

所以我正在尝试在 VBA 中构建这个函数,这就是我目前所拥有的。

Function MAXROWSUM(Ref As Range) As Double
    Dim Result, tempSum As Double
    Dim Started As Boolean
    Started = False
    Result = 0
    For Each Row In Ref.Rows
        tempSum = Application.WorksheetFunction.Sum(Row)
        If (Started = False) Then
            Result = tempSum
            Started = True
        ElseIf tempSum > Result Then
            Result = tempSum
        End If
    Next Row
    MAXROWSUM = Result
End Function

这个函数在少于 100k 行的情况下运行并且非常快,但是如果范围内的行数接近可能的 100 万行,那么即使该范围的大部分是空的,该函数也会变得非常慢,需要几秒钟。 有没有办法通过过滤掉任何空行来显着优化当前代码? 在我的示例中,如果我输入 MAXROWSUM(A1:B1000000) 它将起作用,但会很慢,我可以让它非常快吗?

【问题讨论】:

  • 是的 A1 + B1 = 2,我最初有 ypos,而 C1 是 -2,我已修复。抱歉。
  • @大笨钟。晨盲。我会删除。
  • 感谢@MichaelE 的救援。如果 D3 = Max(Sum(A1+B6)) 则 D3 = Max(C1:C6) 因为 C 列有 A+B。最大值不是 22。
  • @Variatus - MAX(SUM(A1:B6))MAX(A1:A6+B1:B6) 不同(作为数组公式)。
  • @BigBen 想通了——只需要回到基础:这是一道数学题,不是编程题 xD

标签: excel vba excel-formula sum


【解决方案1】:

您的解决方案是Matrix Multiplication,通过the MMULT function

其工作原理如下:目前,您有一个X*N 数组/矩阵,您想将其更改为X*1 矩阵(其中每个新行是旧矩阵中行的总和),然后取最大值。为此,您需要将其乘以 N*1 矩阵:这两个 Ns “取消”。

第一步很简单:第二个矩阵中的每个值都是1

示例:[6*2] ∙ [2*1] = [6*1]

[[-2][ 4]             [[ 2]
 [-1][ 1]    [[ 1]     [ 0]
 [ 0][ 0]  ∙  [ 1]] =  [ 0]
 [ 1][ 1]              [ 2]
 [ 2][ 4]              [ 6]
 [ 3][ 9]]             [12]]

然后我们MAX这个:

=MAX(MMULT(A1:B6,{1;1}))

要动态生成第二个数组(即任何大小),我们可以使用表的第一行,将其完全转换为1(例如,“列号> 0”),然后TRANSPOSE这是一列而不是一行。这可以写成TRANSPOSE(--(COLUMN(A1:B1)>0))

把它们放在一起,我们得到:

=MAX(MMULT(A1:B6, TRANSPOSE(--(COLUMN(A1:B1)>0))))

由于MMULT 与数组一起使用——比如SUMPRODUCT——我们实际上不需要使用 Ctrl+Shift+输入

如果您想改为按列执行此操作,则需要交换数组 - 矩阵乘法不可交换

=MAX(MMULT(TRANSPOSE(--(ROW(A1:A6)>0)), A1:B6))

[1*6] ∙ [6*2] = [2*1]

                              [[-2][ 4]
                               [-1][ 1]
[[ 1][ 1][ 1][ 1][ 1][ 1]]  ∙  [ 0][ 0]   =  [[ 3][19]]
                               [ 1][ 1]
                               [ 2][ 4]
                               [ 3][ 9]]

【讨论】:

  • 效果很好,谢谢。但我仍然需要为 COLUMN(A1:B1) 输入 ctrl-shift-enter。你的工作没有数组公式吗?
  • @MichaelE 是的,它对我来说很好,不需要按 Ctrl+Shift+Enter。我不知道是不是因为我使用的是 Office-365;您使用的是哪个版本的 Excel?
【解决方案2】:

SUMPRODUCT(无名英雄)

以下是不是数组公式。

=SUMPRODUCT(MAX(A:A+A:A^2))

如果它不起作用(旧版 Excel),请更改为确切的范围,例如:

=SUMPRODUCT(MAX(A$1:A$1000+A$1:A$1000^2))

【讨论】:

  • 谢谢,sumproduct 是数组公式的替代方案,但我需要处理大量列,例如 A:Z,而不必直接将它们添加到公式中。
  • @MichaelE:如果你能进一步解释的话。 A1:Z1000 的结果在哪里,除了行之外,它是否应该和我一样?
  • A1:Z1000 可以有任何数字,但是将我的列 b 向右扩展很好,但 x^2 很快就会变得太大。但是,如果您愿意,可以是 A1:A1000+A1:A1000^2 + A1:A1000^3+...+A1:A1000^25
  • @VBasic2008 当值通过一个简单的等式相关时起作用,例如示例 - 但是,如果每一行是一周中的一天,每一列是车间工人,并且值是“销售额”?这种方法无法计算出“每天最多的销售额”。 (另外,这个一个数组公式,但是SUMPRODUCT输出的是计算出来的数组的总和。作为一个正确的数组公式,它只是{=MAX(A:A+A:A^2)}
【解决方案3】:

我找不到使用基本 Excel 执行该功能的方法,所以我不得不使用 VBA。

我能够创建一个运行速度相当快的 VBA 函数。

Function MAXROWSUM(Ref As Range) As Double
    Dim Result, tempSum As Double
    Dim Started As Boolean
    Started = False
    LastDataRow = Ref.Find("*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
    Result = 0
    For Each Row In Ref.Rows
        tempSum = Application.WorksheetFunction.Sum(Row)
        If Row.Row > LastDataRow Then
            Exit For
        End If
        If (Started = False) Then
            Result = tempSum
            Started = True
        ElseIf tempSum > Result Then
            Result = tempSum
        End If
    Next Row
    MAXROWSUM = Result
End Function

关键行是:LastDataRow = Ref.Find("*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row,它查找数据范围的最后填充行并停止函数通过它。所以输入一百万行的函数,其中只有 100 或 1000 行有数据,不会导致过多的无用计算。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-11-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多