如何通过Excel公式获得两个集合的笛卡尔积(交叉连接)

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

我需要通过 Excel 365 公式(不是 VBA,不是 Power Query)获得两个“集合”的 笛卡尔积。例如,我的两个集合是两个左表,预期的笛卡尔积是右表:

Excel 365 中两组的笛卡尔积

Cartesian product of two sets in Excel 365

如何通过一个Excel公式得到笛卡尔积?

如果可能,我想要一个通用答案,适用于任何两个集合,无论它们包含什么值,无论这两个集合中的列数有多少。

两套:

第1栏 第2栏 第1栏 第2栏
4500005010 A PO开始 D
4500005011 B 标题合并 E
4500005012 C PO激活 F
excel excel-formula cartesian-product cross-join
4个回答
3
投票

通用选项可以是:

=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]
参数类似,其中接受以下选项:

  • 0 |不
  • 1 |是的,但不显示
  • 2 |不,但生成
  • 3 |是的并显示

例如:

=CROSSJOIN(Table1,Table2,2)

或者:

=CROSSJOIN(Table1[#All],Table2[#All],3)

请注意,使用换行符和空格/缩进是为了提高可读性。在名称管理器中定义函数时可以将它们删除。


1
投票

不使用

LAMBDA()
辅助功能:

enter image description here


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


1
投票

有一个基于

MAKEARRAY
的解决方案:

Excel formula to get the Cartesian product of two sets in Excel 365

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

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))))

Main Screenshot

TOCOL/IF/序列

效率

  • 我从来没有遇到过这个组合比
    INT/MOD
    组合更有效。不是按原样使用它们(没有明显差异),而是与其他功能结合使用时。
  • 在这种特殊情况下,在两个 1000 行 x 5 列的表上,这个组合花费了 10 秒,而 Mayukh Bhattacharya 的
    INT/MOD
    解决方案(带有
    c, SEQUENCE(a*b),
    的不错的解决方案)花费了 14 秒。您的
    MAKEARRAY
    解决方案花了 23 秒。

TOCOL/IF/SEQUENCE Screenshot

IF/序列

  • 为了更熟悉这个组合,请随时从我的OneDrive下载
    重复专栏
© www.soinside.com 2019 - 2024. All rights reserved.