Google表格中无限真实动态范围平均值的ArrayFormula
Posted
技术标签:
【中文标题】Google表格中无限真实动态范围平均值的ArrayFormula【英文标题】:ArrayFormula of Average on Infinite Truly Dynamic Range in Google Sheets 【发布时间】:2021-04-02 17:28:24 【问题描述】:例如:
A B C D E F G ∞
|======|=======|=====|=====|=====|=====|=====|=====
1 | |AVERAGE| | | | | |
|======|=======|=====|=====|=====|=====|=====|=====
2 | xx 1 | | 1 | 2 | 0.5 | 10 | |
|======|=======|=====|=====|=====|=====|=====|=====
3 | xx 2 | | 7 | 1 | | | |
|======|=======|=====|=====|=====|=====|=====|=====
4 | | | 0 | | | | |
|======|=======|=====|=====|=====|=====|=====|=====
5 | xx 3 | | 9 | 8 | 7 | 6 | |
|======|=======|=====|=====|=====|=====|=====|=====
6 | xx 4 | | 0 | 1 | 2 | 1 | |
|======|=======|=====|=====|=====|=====|=====|=====
7 | | | 1 | | 4 | | |
|======|=======|=====|=====|=====|=====|=====|=====
8 | xx 5 | | | | | | |
|======|=======|=====|=====|=====|=====|=====|=====
9 | | | | | | | 5 |
|======|=======|=====|=====|=====|=====|=====|=====
∞ | | | | | | | |
对于动态意义上的每个有效行(未知数量的行&未知数量的列),获取AVERAGE
的最佳方式是什么?
【问题讨论】:
刚刚意识到你自己问过这个问题。 ???谢谢分享! 【参考方案1】:查询
1 级:
如果 C2:G 范围内的所有 5 个单元格都有值:
=QUERY(QUERY(C2:G, "select (C+D+E+F+G)/5"), "offset 1", )
如果不是,则跳过行:
如果空单元格被视为零:
=INDEX(QUERY(QUERY(C2:G*1, "select (Col1+Col2+Col3+Col4+Col5)/5"), "offset 1", ))
要删除零值,我们使用IFERROR(1/(1/...))
包装:
=INDEX(IFERROR(1/(1/QUERY(QUERY(C2:G*1,
"select (Col1+Col2+Col3+Col4+Col5)/5"), "offset 1", ))))
要使 Col
引用动态,我们可以这样做:
=INDEX(IFERROR(1/(1/QUERY(QUERY(C2:G*1,
"select "&
"("&JOIN("+", "Col"&ROW(INDIRECT("1:"&COLUMNS(C:G))))&")/"&COLUMNS(C:G)),
"offset 1", ))))
2 级:
如果空单元格不被视为零并且不应被跳过:
=INDEX(TRANSPOSE(QUERY(TRANSPOSE(E2:I),
"select "&TEXTJOIN(",", 1, IF(A2:A="",,
"avg(Col"&ROW(A2:A)-ROW(A2)+1&")")))),, 2)
请注意,这取决于 A 列,因此 A 列中的缺失值将抵消结果
有趣的事实!我们可以将avg
换成max
或min
:
将其从 A 列的限制中解放出来并使其适用于任何有效行:
=INDEX(IFERROR(1/(1/TRANSPOSE(QUERY(TRANSPOSE(
IF(TRIM(TRANSPOSE(QUERY(TRANSPOSE(C2:G),,9^9)))="", C2:G*0, C2:G)),
"select "&TEXTJOIN(",", 1,
"avg(Col"&ROW(A2:A)-ROW(A2)+1&")"))))),, 2)
如果范围内的 0 不应该被平均,我们可以添加一个小的 IF 语句:
=INDEX(IFERROR(1/(1/TRANSPOSE(QUERY(TRANSPOSE(
IF(TRIM(TRANSPOSE(QUERY(TRANSPOSE(
IF(C2:G>0, C2:G, )),,9^9)))="", C2:G*0,
IF(C2:G>0, C2:G, ))),
"select "&TEXTJOIN(",", 1,
"avg(Col"&ROW(A2:A)-ROW(A2)+1&")"))))),, 2)
这里我们使用了所谓的“垂直查询粉碎”,它获取给定范围内的所有值并将其集中到一列,其中每行的所有单元格都用空白空间连接起来作为副产品:
=FLATTEN(QUERY(TRANSPOSE(C2:G),,9^9))
除此之外,还有“横向查询粉碎”:
=QUERY(C2:G,,9^9)
还有“终极 360° 双重查询粉碎”,它将范围内的所有单元格放在一个单元格中:
=QUERY(FLATTEN(QUERY(TRANSPOSE(C2:G),,9^9)),,9^9)
最后是“臭名昭著的负 360° 反向双重查询粉碎”,它将列优先于行:
=QUERY(FLATTEN(QUERY(C2:G,,9^9)),,9^9)
所有查询粉碎名称当然都受版权保护
回到主题...如上所述,范围内每行的所有单元格都与空白空间相连,即使是那些空白的,所以我们遇到了一种情况,即值之间有两个或多个空格。为了解决这个问题,我们使用TRIM
并引入一个简单的IF
语句来为给定范围内的空行分配0 值,例如。抵消偏移量:
MMULT
3 级:
MMULT
是一种重类公式,它能够执行加法、减法、乘法、除法甚至对数组/矩阵求和...但是,更大的数据集 = 更慢的公式计算(因为在 @987654397 @ 即使是空行也需要时间来执行 + - × ÷
操作)...除非我们在两个方向上使用真正的动态范围无限...
获取具有给定范围值的最后一行:
=INDEX(MAX(IF(TRIM(FLATTEN(QUERY(TRANSPOSE(
INDIRECT("C2:"&ROWS(A:A))),,9^9)))="",,ROW(A2:A))))
获取具有给定范围值的最后一列:
=INDEX(MAX(IF(TRIM(QUERY(INDIRECT("C2:"&ROWS(A:A)),,9^9))="",,COLUMN(C2:2))))
现在我们可以用一种简单的方式构造它:
=INDIRECT("C2:"&ADDRESS(9, 7))
等同于:
=INDEX(INDIRECT("C2:"&ADDRESS(MAX(IF(TRIM(FLATTEN(QUERY(TRANSPOSE(
INDIRECT("C2:"&ROWS(A:A))),,9^9)))="",,ROW(A2:A))),
MAX(IF(TRIM(QUERY(INDIRECT("C2:"&ROWS(A:A)),,9^9))="",,COLUMN(C2:2))))))
或更短的替代:
=INDEX(INDIRECT("C2:"&ADDRESS(
MAX((INDIRECT("C2:"&ROWS(A:A))<>"")*ROW(A2:A)),
MAX((INDIRECT("C2:"&ROWS(A:A))<>"")*COLUMN(C2:2)))))
因此简化的 MMULT 公式为:
=ARRAYFORMULA(IFERROR(
MMULT(N( C2:G9), ROW(INDIRECT("C1:C"&COLUMNS(C:G)))^0)/
MMULT(N(IF(C2:G9<>"", 1, )), ROW(INDIRECT("C1:C"&COLUMNS(C:G)))^0)))
如果我们想从范围中排除零值,公式为:
=ARRAYFORMULA(IFERROR(
MMULT(N( C2:G9), ROW(INDIRECT("C1:C"&COLUMNS(C:G)))^0)/
MMULT(N(IF(C2:G9>0, 1, )), ROW(INDIRECT("C1:C"&COLUMNS(C:G)))^0)))
4 级:
将以上所有内容组合在一起,使其无限动态,但仍仅限于有效数据集:
=INDEX(IFERROR(
MMULT(N( INDIRECT("C2:"&ADDRESS(
MAX((INDIRECT("C2:"&ROWS(A:A))<>"")*ROW(A2:A)),
MAX((INDIRECT("C2:"&ROWS(A:A))<>"")*COLUMN(C2:2))))), ROW(INDIRECT("C1:C"&
MAX((INDIRECT("C2:"&ROWS(A:A))<>"")*COLUMN(C2:2))-(COLUMN(C2)-1)))^0)/
MMULT(N(IF(INDIRECT("C2:"&ADDRESS(
MAX((INDIRECT("C2:"&ROWS(A:A))<>"")*ROW(A2:A)),
MAX((INDIRECT("C2:"&ROWS(A:A))<>"")*COLUMN(C2:2))))<>"", 1, )), ROW(INDIRECT("C1:C"&
MAX((INDIRECT("C2:"&ROWS(A:A))<>"")*COLUMN(C2:2))-(COLUMN(C2)-1)))^0)))
同样,不包括范围内为零的单元格:
荣誉奖:
@Erik Tyler级别:
与上一个公式相反的是运行MMULT
C2:?
(all rows, all columns)
的总面积而不是
有效区域C2:?
(excluding empty rows and columns)
避免0 × 0 = 0
的质量计算
包括零:
=INDEX(IFERROR(
MMULT( INDIRECT("C2:"&ROWS(C:C))*1, SEQUENCE(COLUMNS(C2:2))^0)/
MMULT(IF(INDIRECT("C2:"&ROWS(C:C))<>"", 1)*1, SEQUENCE(COLUMNS(C2:2))^0)))
不包括零:
=INDEX(IFERROR(
MMULT( INDIRECT("C2:"&ROWS(C:C))*1, SEQUENCE(COLUMNS(C2:2))^0)/
MMULT(IF(INDIRECT("C2:"&ROWS(C:C))>0, 1)*1, SEQUENCE(COLUMNS(C2:2))^0)))
@kishkin级别:
对于固定范围C2:G9
,MMULT
的平均值为:
=INDEX(IFERROR(
MMULT( C2:G9*1, FLATTEN(COLUMN(C:G))^0)/
MMULT((C2:G9>0)*1, FLATTEN(COLUMN(C:G))^0)))
=INDEX(IFNA(VLOOKUP(ROW(C2:C),
QUERY(SPLIT(FLATTEN(ROW(C2:C)&"×"&C2:J), "×"),
"select Col1,avg(Col2)
where Col2 is not null
group by Col1"), 2, )))
@MattKing级别:
=INDEX(QUERY(SPLIT(FLATTEN(ROW(C2:C)&"×"&OFFSET(C2,,,9^9, 9^9)), "×"),
"select avg(Col2)
group by Col1
label avg(Col2)''"))
不包括零:
=INDEX(QUERY(SPLIT(FLATTEN(ROW(C2:C)&"×"&OFFSET(C2,,,9^9, 9^9)), "×"),
"select avg(Col2)
where Col2 <> 0
group by Col1
label avg(Col2)''"))
包括空单元格:
=INDEX(IFERROR(1/(1/QUERY(SPLIT(FLATTEN(ROW(C2:C)&"×"&OFFSET(C2,,,9^9, 9^9)*1), "×"),
"select avg(Col2)
group by Col1
label avg(Col2)''"))))
【讨论】:
如果您有时间请咨询=INDEX(MAX(IF(TRIM(FLATTEN(QUERY(TRANSPOSE( INDIRECT("C2:"&ROWS(A:A))),,9^9)))="",,ROW(A2:A))))
。 1. INDIRECT(...)
是否比 OFFSET(C2, 0, 0, ROWS(C2:C), COLUMNS(C2:2))
更好? 2.FLATTEN
这里只是转置了QUERY
的结果,为什么不用TRANSPOSE
呢?
@kishkin 当然。 FLATTEN
的字符数少于 TRANSPOSE
:D 与 INDEX
与 ARRYFORMULA
相同。正如 MattKing 几周前提到的那样,FLATTEN
将永远留在 GS,所以它现在是官方的 fx。至于OFFSET(...)
那也比INDIRECT(...)
长-没有其他理由。它只是一个简短的选择
感谢您的解释!并且在各个方面都是一个很好的答案!一些注意事项:在IF
中不需要IF(C2:G9>0, 1)*1
(和类似的),可能只是(C2:G9>0)*1
; 2.你不要过滤掉内部的空列和行,以防有一些:)。可以通过VLOOKUP(ROW(B2:B), non_empty_row_numbers, avg_on_totally_filtered_out_range, 2, 0)
完成。还是太多了?
@kishkin 确实,这是有道理的。而对于VLOOKUP
...我并没有想到...我更专注于寻找外部边界。无论如何,这是一种有趣的方法,但让我想知道它如何在具有 20k+ 行的巨大数据集上以速度表现。我肯定有一天会测试它。【参考方案2】:
您为此投入了大量时间。我希望人们欣赏它,更希望你这样做是为了其他人,而不是为了你自己。
看看你的最终公式,这些应该产生相同的结果(在 C2:? 中给出数据,就像你的例子一样):
在 B2 中(包括零):
=ArrayFormula(IFERROR(MMULT(INDIRECT("C2:"&ROWS(C:C))*1,SEQUENCE(COLUMNS(C1:1),1,1,0))/ MMULT(IF(INDIRECT("C2:"&ROWS(C:C))<>"",1,0),SEQUENCE(COLUMNS(C1:1),1,1,0))))
在 B2 中(不包括零):
=ArrayFormula(IFERROR(MMULT(INDIRECT("C2:"&ROWS(C:C))*1,SEQUENCE(COLUMNS(C1:1),1,1,0))/ MMULT(IF(INDIRECT("C2:"&ROWS(C:C))<>0,1,0),SEQUENCE(COLUMNS(C1:1),1,1,0))))
【讨论】:
虽然这是一个有趣的公式大小缩减,但计算出的矩阵将包括C2:?(all rows, all columns)
的总面积,而不是有效面积 C2:?(excluding empty rows and columns)
例如。避免 0 × 0 = 0 的质量计算
在 5000 行 x 50 列的网格中运行所需的计算时间不到一秒。人们试图计算这么大范围的数字的可能性非常小。当然,可以通过添加一个或两个字符(例如,将 C1:1 更改为 C1:M1、C:C 更改为 C2:C500 等)来“控制”适用字段以反映其实际最大值要处理的已知范围。那么,在实际使用中,无论是否添加公式,这些都可以使用。
但是,我将所有这些公式视为人们学习和尝试事物的机会,而不是“最佳实践”。如果人们想花时间分解它们,你解释功能、原因和原因的详尽工作将大有帮助,因为你提供了很好的背景。
同意。可悲的是,一年后这将获得大约 200 次观看 xD【参考方案3】:
更新:我已经更新了原始帖子中的公式。 ROW() 应该始终排在第一位,这样数据中的缺失值就不会导致拆分。
=ARRAYFORMULA(QUERY(SPLIT(FLATTEN(ROW(C2:C)&"|"&OFFSET(C2,,,9^9,9^9)),"|"),"select AVG(Col2) group by Col1 label AVG(Col2)''"))
应该有效,除非我误解了这个问题。
不需要 vlookups 或 mmults 或过滤器或任何东西。
【讨论】:
不错的一个。如果某行包含全空单元格,这将抵消最终输出。另外,我需要用where Col2 is not null
扩展它,因为第一个值被搞砸了 - i.stack.imgur.com/9EScK.png
@player0 它不会用整行中的所有空单元格抵消最终输出。我已经测试了一堆。唯一需要的是大多数值不能为空。
@MattKing 你忘记了SPLIT
末尾的几个逗号。否则(如果原始数据单元格为空),您有时会在第一列中获得行号,因为SPLIT
会删除空结果。 i.imgur.com/xECBRWs.png
@kishkin 啊,你写的。当我第一次这样做时,我先写了行号,所以我不需要那些额外的逗号。 (因为 ROW() 永远不会为空)我现在会改变我的答案。希望这也能为玩家 0 解决问题
@player0 更新了公式。我忘记了你需要 ROW() 是第一个。再试一次【参考方案4】:
我会尝试对@player0 的回答做一点补充。我将非常感谢任何 cmet 对此进行优化。
如果数据范围内有很多空行和列,不妨从MMULT
中排除。
第 1 步 - 过滤掉空行
我们有一个数据范围:从C2
到最后一行,再到最后一列(即J:J
)。我将使用C2:K
,详细解释见下文。
这个公式将为我们提供一个行号数组,其中至少有一个非空单元格。如果有空行,它也会有一个0
,但是在这个数组中搜索并不重要,或者我们会在重要时将其过滤掉:
=ARRAYFORMULA(
UNIQUE(FLATTEN((C2:K <> "") * ROW(C2:K)))
)
因此,为了从数据范围中过滤掉空行,我们使用FILTER
从上方检查我们的数组中是否有一行,如果在这种情况下则离开:
=ARRAYFORMULA(
FILTER(
C2:K*1,
MATCH(
ROW(C2:K),
UNIQUE(FLATTEN((C2:K <> "") * ROW(C2:K))),
0
)
)
)
第 2 步 - 过滤掉空列
要获得一个只有非空列号的数组,我们可以使用几乎相同的公式:
=ARRAYFORMULA(
UNIQUE(FLATTEN((C2:K <> "") * SEQUENCE(1, COLUMNS(C2:K), COLUMN(C2))))
)
为什么使用SEQUENCE(1, COLUMNS(C2:K), COLUMN(C2))
而不是COLUMN(C2:K)
详见文末。
为了过滤掉空列,我们还使用FILTER
和MATCH
条件来搜索我们数组中的列号:
=ARRAYFORMULA(
FILTER(
C2:K*1,
MATCH(
SEQUENCE(1, COLUMNS(C2:K), COLUMN(C2)),
UNIQUE(FLATTEN((C2:K <> "") * SEQUENCE(1, COLUMNS(C2:K), COLUMN(C2)))),
0
)
)
)
为了过滤掉空行和空列,我们只使用两个FILTER
s:
=ARRAYFORMULA(
FILTER(
FILTER(
C2:K*1,
MATCH(
ROW(C2:K),
UNIQUE(FLATTEN((C2:K <> "") * ROW(C2:K))),
0
)
),
MATCH(
SEQUENCE(1, COLUMNS(C2:K), COLUMN(C2)),
UNIQUE(FLATTEN((C2:K <> "") * SEQUENCE(1, COLUMNS(C2:K), COLUMN(C2)))),
0
)
)
)
原始数据范围将在内部变为:
第 3 步 - 执行MMULT
现在我们可以使用 MMULT
和该数据集来计算平均值:
=ARRAYFORMULA(
MMULT(
FILTER(
FILTER(
C2:K*1,
MATCH(
ROW(C2:K),
UNIQUE(FLATTEN((C2:K <> "") * ROW(C2:K))),
0
)
),
MATCH(
SEQUENCE(1, COLUMNS(C2:K), COLUMN(C2)),
UNIQUE(FLATTEN((C2:K <> "") * SEQUENCE(1, COLUMNS(C2:K), COLUMN(C2)))),
0
)
),
SEQUENCE(
ROWS(
QUERY(
UNIQUE(FLATTEN((C2:K <> "") * SEQUENCE(1, COLUMNS(C2:K), COLUMN(C2)))),
"WHERE Col1 <> 0"
)
),
1,
1,
0
)
) /
MMULT(
FILTER(
FILTER(
(C2:K <> "")*1,
MATCH(
ROW(C2:K),
UNIQUE(FLATTEN((C2:K <> "") * ROW(C2:K))),
0
)
),
MATCH(
SEQUENCE(1, COLUMNS(C2:K), COLUMN(C2)),
UNIQUE(FLATTEN((C2:K <> "") * SEQUENCE(1, COLUMNS(C2:K), COLUMN(C2)))),
0
)
),
SEQUENCE(
ROWS(
QUERY(
UNIQUE(FLATTEN((C2:K <> "") * SEQUENCE(1, COLUMNS(C2:K), COLUMN(C2)))),
"WHERE Col1 <> 0"
)
),
1,
1,
0
)
)
)
关于原始数据行有点偏离。
第 4 步 - 填写平均列
为了使平均值与原始数据行一致,我们可以像这样使用VLOOKUP
:
=ARRAYFORMULA(
IFNA(VLOOKUP(
SEQUENCE(MAX((C2:K <> "") * ROW(C2:K)) - 1, 1, ROW(C2)),
QUERY(UNIQUE(FLATTEN((C2:K <> "") * ROW(C2:K))), "WHERE Col1 <> 0"),
MMULT(
...
) /
MMULT(
...
)
,
2,
0
))
)
在哪里
SEQUENCE(MAX((C2:K <> "") * ROW(C2:K)) - 1, 1, ROW(C2))
是从第二个到最后一个非空的行号数组。我们不会用空字符串填充所有行。
QUERY(UNIQUE(FLATTEN((C2:K <> "") * ROW(C2:K))), "WHERE Col1 <> 0")
是一个非空行号数组,过滤掉的 0
用作搜索键。
IFNA
将返回一个空字符串以放在一个空数据行旁边。
最终公式
把它们放在一起:
=ARRAYFORMULA(
IFNA(VLOOKUP(
SEQUENCE(MAX((C2:K <> "") * ROW(C2:K)) - 1, 1, ROW(C2)),
QUERY(UNIQUE(FLATTEN((C2:K <> "") * ROW(C2:K))), "WHERE Col1 <> 0"),
MMULT(
FILTER(
FILTER(
C2:K*1,
MATCH(
ROW(C2:K),
UNIQUE(FLATTEN((C2:K <> "") * ROW(C2:K))),
0
)
),
MATCH(
SEQUENCE(1, COLUMNS(C2:K), COLUMN(C2)),
UNIQUE(FLATTEN((C2:K <> "") * SEQUENCE(1, COLUMNS(C2:K), COLUMN(C2)))),
0
)
),
SEQUENCE(
ROWS(
QUERY(
UNIQUE(FLATTEN((C2:K <> "") * SEQUENCE(1, COLUMNS(C2:K), COLUMN(C2)))),
"WHERE Col1 <> 0"
)
),
1,
1,
0
)
) /
MMULT(
FILTER(
FILTER(
(C2:K <> "")*1,
MATCH(
ROW(C2:K),
UNIQUE(FLATTEN((C2:K <> "") * ROW(C2:K))),
0
)
),
MATCH(
SEQUENCE(1, COLUMNS(C2:K), COLUMN(C2)),
UNIQUE(FLATTEN((C2:K <> "") * SEQUENCE(1, COLUMNS(C2:K), COLUMN(C2)))),
0
)
),
SEQUENCE(
ROWS(
QUERY(
UNIQUE(FLATTEN((C2:K <> "") * SEQUENCE(1, COLUMNS(C2:K), COLUMN(C2)))),
"WHERE Col1 <> 0"
)
),
1,
1,
0
)
)
,
2,
0
))
)
一些细节
为简洁起见,可以使用INDEX
代替 ARRAYFORMULA
(感谢 @player0,几个月前教我),但我喜欢 ARRAYFORMULA
的明确性。
为了清楚起见,我使用SEQUENCE
来构造1
s 的列或行以明确。比如这个
SEQUENCE(
ROWS(
QUERY(
UNIQUE(FLATTEN((C2:K <> "") * SEQUENCE(1, COLUMNS(C2:K), COLUMN(C2)))),
"WHERE Col1 <> 0"
)
),
1,
1,
0
)
可以替换为
SIGN(
QUERY(
UNIQUE(FLATTEN((C2:K <> "") * SEQUENCE(1, COLUMNS(C2:K), COLUMN(C2)))),
"WHERE Col1 <> 0"
)
)
这有点短。 @player0 在这里还展示了一种提升到0
力量的方法:
QUERY(
UNIQUE(FLATTEN((C2:K <> "") * SEQUENCE(1, COLUMNS(C2:K), COLUMN(C2)))),
"WHERE Col1 <> 0"
)^0
但是(这只是我的猜测)我认为SEQUENCE
的内部实现应该比提升到幂的操作更简单。
C2:K
,它比工作表上实际存在的列多一列。它不仅给出了C2
右侧的所有列及其下方的所有行的范围,而且在工作表右侧添加另一列时它也会更新:a demo。虽然它不会被突出显示。这个C2:K
几乎可以完美地替代这些方法(如果工作表上实际上存在ZZZ
列,则会出现问题):
INDIRECT("C2:" & ROWS(C:C))
OFFSET(C2,,, ROWS(C2:C), COLUMNS(C2:2))
使用C2:K
有一个小缺点:=ARRAYFORMULA(COLUMN(C2:K))
将返回一个列号数组,即使是不存在的列号,所以我们需要改用=SEQUENCE(1, COLUMNS(C2:K), COLUMN(C2))
。
【讨论】:
【参考方案5】:我认为使用VLOOKUP
和QUERY
的逐行平均有一个简单的答案。
这个在B2
:
=ARRAYFORMULA(
IFNA(
VLOOKUP(
ROW(B2:B),
QUERY(
FLATTEN(ROW(C2:J) + SEQUENCE(1, COLUMNS(C2:J),,)),
FLATTEN(C2:J)
,
"SELECT Col1, AVG(Col2)
WHERE Col2 IS NOT NULL
GROUP BY Col1"
),
2,
0
)
)
)
这可以轻松更改为 max、min、sum、count - 只需更改 QUERY
语句中的聚合函数。
同样的方法可用于按列聚合。
FLATTEN(C2:J)
可以更改为:
FLATTEN(--C2:J)
将空单元格视为0
s;
FLATTEN(IFERROR(1/(1/C2:J)))
从平均值中排除 0
s。
如果没有中间空行,则可以从公式中删除VLOOKUP
,以及从SELECT
语句中删除Col1
。
有一个没有VLOOKUP
和WHERE Col...
的较短版本(感谢@MattKing!):
=ARRAYFORMULA(
QUERY(
FLATTEN(ROW(C2:J) + SEQUENCE(1, COLUMNS(C2:J),,)),
FLATTEN(IFERROR(1/(1/C2:J)))
,
"SELECT AVG(Col2)
GROUP BY Col1
LABEL AVG(Col2) ''"
)
)
我使用C2:J
范围,其列最多为I:I
,有关此的一些详细信息:
C2:J
比工作表上实际存在的列多一列。它不仅给出了C2
右侧的所有列及其下方的所有行的范围,而且在工作表右侧添加另一列时也会更新:a demo。虽然它不会被突出显示。这个C2:J
几乎可以完美地替换这些方法(如果工作表上实际上存在ZZZ
列,则会出现问题):
INDIRECT("C2:" & ROWS(C:C))
OFFSET(C2,,, ROWS(C2:C), COLUMNS(C2:2))
使用C2:J
有一个小缺点:=ARRAYFORMULA(0 * COLUMN(C2:J))
将返回一个列号数组,即使是不存在的列号(乘以0
),所以我们需要改用=SEQUENCE(1, COLUMNS(C2:J),,)
。李>
@player0,对此有什么想法吗?
【讨论】:
我确实喜欢它 如果你想检查的话,我把它缩短了大约 30 个字符,并且没有太多的数学运算:docs.google.com/spreadsheets/d/… @player0 不错!删除所有\s
is fun! :) 顺便说一句,\s
包括 \n
。
@player0 我用数学(你的意思是+
和SEQUENCE
,对吗?)是明确的,我尽量避免join-split(50k个字符限制,不能在我的数据中使用♥ )。还有一个相邻的更复杂的问题,我用MOD
和SEQUENCE
解决了,不确定是否有更简单的解决方案。与列步长的逐行求和,如果好奇,2nd sheet in A3
。
50k 限制适用于 JOIN、TEXTJOIN、TRIM、REGEXREPLACE、SUBSTITUTE 等,但如果您使用 &
或 QUERY
,则不会 - 在这种情况下,没有限制。是的,对于数学部分...有时感觉数学会减慢对极其庞大的数据集的计算速度,即使它很简单,例如 0*1。你到那里的有趣的 MOD 用法以上是关于Google表格中无限真实动态范围平均值的ArrayFormula的主要内容,如果未能解决你的问题,请参考以下文章
使用 Google 表格中的单个公式从范围创建动态排序和过滤列表