很酷的问题和脑筋急转弯;我只是对正在使用的东西感到困惑MAKEARRAY()
:
选项1:
您所说的“超级低效”是在计算行^列时创建排列列表。我认为下面的方法并没有那么低效。让我们想象一下以下情况:
公式为E1
:
=LET(A,A1:C3,B,ROWS(A),C,COLUMNS(A),D,B^C,E,UNIQUE(MAKEARRAY(D,C,LAMBDA(rw,cl,INDEX(IF(A="","",A),MOD(CEILING(rw/(D/(B^cl)),1)-1,B)+1,cl)))),FILTER(E,MMULT(--(E<>""),SEQUENCE(C,,,0))=C))
简而言之,它的作用是:
- 变量 A-D 都是辅助变量。
- 然后的想法是只使用简单的
INDEX()
s 返回所有值。为此,我们需要行和列的正确索引。
-
MAKEARRAY()
由于 lambda 带来的递归功能,将使计算相对容易。在这些函数内部,其基本数学运算返回这些行和列的正确索引。事实上,列不需要计算,因为我们只是引用“cl”,并且所有行索引的所有计算都是通过MOD(CEILING(rw/(D/(B^cl)),1)-1,B)+1
.
- 将上面的结果代入
UNIQUE()
使用很少的资源来过滤掉任何潜在的重复项and将潜在的空行限制为一个空行。
-
FILTER()
and MMULT()
很好地协同工作,过滤掉任何不需要的结果(读;空)。
这是我认为我能得到的那样紧凑和快速。该公式现在适用于任何连续的单元格范围。单个单元格、单行、单列或任何二维范围。
选项2:
OP 正确地提到,选项 1 可能会在开始时创建太多元组,然后才丢弃它们。这可能效率低下。为了解决这个问题(如果这不是您想要的),我们可以使用更大的公式。让我们想象一下以下数据:
A |
B |
C |
a |
d |
f |
b |
e |
h |
|
e |
|
c |
|
g |
|
|
g |
我们看到有空单元格和重复值。这些就是选项 1 创建过多元组的原因。为了反驳这一点,我想出了一个更长的公式:
=LET(A,A1:C5,B,ROWS(A),C,COLUMNS(A),D,IF(A="",NA(),A),E,MAKEARRAY(B,C,LAMBDA(rw,cl,INDEX(SORT(INDEX(D,0,cl)),rw))),F,BYCOL(E,LAMBDA(cl,COUNTA(FILTER(cl,NOT(ISERROR(cl)))))),G,MAKEARRAY(PRODUCT(F),C,LAMBDA(rw,cl,INDEX(E,MOD(CEILING(rw/IFERROR(PRODUCT(INDEX(F,SEQUENCE(C-cl,,cl+1))),1),1)-1,INDEX(F,cl))+1,cl))),UNIQUE(G))
分解一下:
-
LET()
- 使用变量;
-
A
- 我们最初的全范围细胞(连续);
-
B
- A的总行数;
-
C
- A的列总数;
-
D
- 公式IF(A="",NA(),A)
旨在检查矩阵中的每个值是否为空(字符串)。如果是这样,请将其设为错误(这将在下一步中有意义)。
-
E
- 在这一步中,公式MAKEARRAY(B,C,LAMBDA(rw,cl,INDEX(SORT(INDEX(D,0,cl)),rw)))
正在对每一列进行排序,因此值位于顶部,所有错误都被推到下面:
A |
B |
C |
a |
d |
f |
b |
e |
g |
c |
e |
g |
#N/A |
#N/A |
h |
#N/A |
#N/A |
#N/A |
-
F
- 该变量的公式BYCOL(E,LAMBDA(cl,COUNTA(FILTER(cl,NOT(ISERROR(cl))))))
现在将计算每列的项目数量。这是稍后使用和计算所有排列所必需的。在这个特定案例中的结果将是{3;3;4}
.
-
G
- 最后一个变量(如果选择这样使用它)使用MAKEARRAY(PRODUCT(F),C,LAMBDA(rw,cl,INDEX(E,MOD(CEILING(rw/IFERROR(PRODUCT(INDEX(F,SEQUENCE(C-cl,,cl+1))),1),1)-1,INDEX(F,cl))+1,cl)))
。虽然很长,但每一步都很有意义;获取乘积(所有可能的排列)来计算行总数,列保持不变。在里面LAMBDA()
我们引用当前列索引之后的所有列F
多变的。这是一个相当大的块需要消化,不幸的是我解释得不够好=)。
-
UNIQUE(G)
- 最后一步是过滤掉所有双重排列(如果有人选择的话)。
结果:
现在,尽管选项 1 在可读性方面胜过选项 2,但第二个选项(经过非常有限的测试)计算时间仅为第一个选项的三分之一。因此,就速度而言,第二种选择是首选。
作为第二个选项的替代方案,我首先有:
=LET(A,A1:C5,B,ROWS(A),C,COLUMNS(A),D,MAKEARRAY(B,C,LAMBDA(rw,cl,IF(MATCH(INDEX(A,rw,cl),INDEX(A,0,cl),0)=rw,INDEX(A,rw,cl),NA()))),E,MAKEARRAY(B,C,LAMBDA(rw,cl,INDEX(SORT(INDEX(D,0,cl)),rw))),F,BYCOL(E,LAMBDA(cl,COUNTA(UNIQUE(FILTER(cl,NOT(ISERROR(cl))))))),G,MAKEARRAY(PRODUCT(F),C,LAMBDA(rw,cl,INDEX(E,MOD(CEILING(rw/IFERROR(PRODUCT(INDEX(F,SEQUENCE(C-cl,,cl+1))),1),1)-1,INDEX(F,cl))+1,cl))),G)
现在这将改变D
变量为更长的公式以预先删除每列中的重复项。两种变体都可以很好地工作。