我需要通过 Excel 365 公式(不是 VBA,不是 Power Query)获得两个“集合”的 笛卡尔积。例如,我的两个集合是两个左表,预期的笛卡尔积是右表:
Excel 365 中两组的笛卡尔积
如何通过一个Excel公式得到笛卡尔积?
如果可能,我想要一个通用答案,适用于任何两个集合,无论它们包含什么值,无论这两个集合中的列数有多少。
两套:
第1栏 | 第2栏 | 第1栏 | 第2栏 | |
---|---|---|---|---|
4500005010 | A | PO开始 | D | |
4500005011 | B | 标题合并 | E | |
4500005012 | C | PO激活 | F |
通用选项可以是:
=CROSSJOIN(Table1,Table2)
其中
CROSSJOIN
是名称管理器中定义的自定义函数:
=LAMBDA(array1,array2,
LET(
i, SEQUENCE(ROWS(array1)),
j, SEQUENCE(, ROWS(array2)),
HSTACK(
CHOOSEROWS(array1, TOCOL(IF(j, i))),
CHOOSEROWS(array2, TOCOL(IF(i, j)))
)
)
)
来源:https://stackoverflow.com/a/78244826/22459970
如果您还想要处理标题行的选项,
CROSSJOIN
可以定义如下:
=LAMBDA(array1,array2,[headers],
LET(
incl_h, CHOOSE(headers + 1, 0, 1, 0, 1),
show_h, CHOOSE(headers + 1, 0, 0, 1, 1),
a, DROP(array1, incl_h),
b, DROP(array2, incl_h),
i, SEQUENCE(ROWS(a)),
j, SEQUENCE(, ROWS(b)),
v, HSTACK(
CHOOSEROWS(a, TOCOL(IF(j, i))),
CHOOSEROWS(b, TOCOL(IF(i, j)))
),
IF(
show_h,
VSTACK(
IF(
incl_h,
HSTACK(
TAKE(array1, 1),
TAKE(array2, 1)
),
HSTACK(
"tbl1.Col" & SEQUENCE(, COLUMNS(a)),
"tbl2.Col" & SEQUENCE(, COLUMNS(b))
)
),
v
),
v
)
)
)
可选的 [headers] 参数的行为方式与 GROUPBY
的
[field_headers]参数类似,其中接受以下选项:
例如:
=CROSSJOIN(Table1,Table2,2)
或者:
=CROSSJOIN(Table1[#All],Table2[#All],3)
请注意,使用换行符和空格/缩进是为了提高可读性。在名称管理器中定义函数时可以将它们删除。
不使用
LAMBDA()
辅助功能:
=LET(
a, TOROW(DataTwo[Column1]&"|"&DataTwo[Column2]),
b, TOCOL(DataOne[Column1]&"|"&DataOne[Column2]&"|"&a),
TEXTSPLIT(TEXTAFTER("|"&b,"|",SEQUENCE(,4)),"|"))
• 或者,选项二:
=LET(
a, ROWS(DataTwo),
b, ROWS(DataOne),
c, CHOOSEROWS(DataOne,INT((SEQUENCE(a*b)-1)/a)+1),
d, CHOOSEROWS(DataTwo,MOD((SEQUENCE(a*b)-1),a)+1),
HSTACK(c,d))
最后更改变量进行评估:
=LET(
a, ROWS(DataTwo),
b, ROWS(DataOne),
c, SEQUENCE(a*b),
d, CHOOSEROWS(DataOne,INT((c-1)/a)+1),
e, CHOOSEROWS(DataTwo,MOD((c-1),a)+1),
f, HSTACK(d,e),
f)
MAKEARRAY
的解决方案:
=MAKEARRAY(
ROWS(Set_1)*ROWS(Set_2),
COLUMNS(Set_1)+COLUMNS(Set_2),
LAMBDA(row,col,
LET(set_num,IF(col<=COLUMNS(Set_1),1,2),CHOOSE(set_num,
INDEX(Set_1,QUOTIENT(row-1,3)+1,col),
INDEX(Set_2,MOD(row-1,3)+1,col-COLUMNS(Set_1))))))
=LET(data1,Table11,data2,Table12,
Repeat,LAMBDA(fs,ss,by_col,
TOCOL(IF(TOROW(ss),fs),,by_col)),
fs,SEQUENCE(ROWS(data1)),
ss,SEQUENCE(ROWS(data2)),
HSTACK(CHOOSEROWS(data1,Repeat(fs,ss,0)),
CHOOSEROWS(data2,Repeat(ss,fs,1))))
TOCOL/IF/序列
效率
INT/MOD
组合更有效。不是按原样使用它们(没有明显差异),而是与其他功能结合使用时。INT/MOD
解决方案(带有 c, SEQUENCE(a*b),
的不错的解决方案)花费了 14 秒。您的MAKEARRAY
解决方案花了 23 秒。IF/序列
OneDrive
下载重复专栏。