如何在Excel中的数组公式中进行逐行求和?

问题描述 投票:0回答:4

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

    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 求和并给出最终的行宽度最大值。

我只能使用基础 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) 它将起作用,但会很慢,我可以使其变得非常快吗?

excel vba excel-formula sum
4个回答
7
投票

您的解决方案是矩阵乘法,通过

MMULT
函数

其工作原理如下:当前,您有一个

X*N
数组/矩阵,您想要将其更改为
X*1
矩阵(其中每个新行都是旧矩阵中的行之和),然后取最大值。为此,您需要将其乘以
N*1
矩阵:两个
N
“抵消”。

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

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+Enter 将其定义为数组公式!

如果您想按列进行此操作,那么您需要交换数组 - 矩阵乘法是不可交换的

=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]]

1
投票

SUMProduct(无名英雄)

以下是不是数组公式。

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

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

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

0
投票

我找不到用基本 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 行有数据,不会导致过多的无用计算。


0
投票

如果您的 Excel 版本允许数组公式,您无需使用 VBA 即可使用

LET
:

= LET(
    \formula, "Returns a vector of row/col sum of the given matrix.",
    input_your_matrix, select_your_matrix_here,
    input_sum_per_row, TRUE,    \comment, "Otherwise sum per columns.",
    \user, "Done!",
    
    m, input_your_matrix,
    b, input_sum_per_row,
    mT, IF( b, m, TRANSPOSE( m ) ),
    k, IF( b, COLUMNS( m ), ROWS( m ) ),
    s, SEQUENCE( k, 1, 1, 0 ),
    sum, MMULT( mT, s ),
    o, IF( b, sum, TRANSPOSE( sum ) ),
    output, o,
    output )

上面的公式有 2 个输入(每个输入都在后续公式参数中定义):

  1. input_your_matrix
    是您要计算总和的数据
  2. input_sum_per_row
    设置为
    TRUE
    对行求和,
    FALSE
    对列求和

为了回答你的例子,我将使用上面提出的

LET
公式:

  • 在单元格
    C1
    中,并将
    select_your_matrix_here
    替换为
    A1:B6
    (它会溢出
    C1:C6
  • 如果你只关心
    D1
    的结果,你可以简单地用
    LET
    包裹
    MAX
© www.soinside.com 2019 - 2024. All rights reserved.