假设我有以下基本电子表格:
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) 它将起作用,但会很慢,我可以使其变得非常快吗?
您的解决方案是矩阵乘法,通过
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]]
以下是不是数组公式。
=SUMPRODUCT(MAX(A:A+A:A^2))
如果不起作用(旧版 Excel),请更改为确切的范围,例如:
=SUMPRODUCT(MAX(A$1:A$1000+A$1:A$1000^2))
我找不到用基本 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 行有数据,不会导致过多的无用计算。
如果您的 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 个输入(每个输入都在后续公式参数中定义):
input_your_matrix
是您要计算总和的数据input_sum_per_row
设置为 TRUE
对行求和,FALSE
对列求和为了回答你的例子,我将使用上面提出的
LET
公式:
C1
中,并将select_your_matrix_here
替换为A1:B6
(它会溢出C1:C6
)D1
的结果,你可以简单地用LET
包裹
MAX