我们如何在 MS Excel 中执行常见的集合运算(并、交、减)?

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

例如,我有一个 xls,其中:

  • A 列包含具有属性 A 的项目列表
  • B 列包含具有属性 B 的项目列表

我需要以下内容:

  • C 列是 A 并集 B(A 和 B 的唯一项)
  • D 列是 A 交集 B(A 和 B 的共同项)
  • E 列是 A 减去 B(A 中的项目但 B 中不存在的项目)
  • F 列是 B 减去 A(B 中的项目但 A 中不存在)

使用 SQL 或 Python 对元素列表进行设置操作似乎很容易。但是如何在xls中做到这一点呢?

注意:它应该是一种自动化,只需最少的复制粘贴和点击。例如,我不想将 A 复制粘贴到 B 下面,然后“消除重复项”以获得 A 并集 B。

excel statistics analytics
6个回答
15
投票

交叉口(A 和 B):

=IFNA(VLOOKUP(B2,$A$2:$B$42,1,FALSE),"")

联合(在 A 或 B 中):

=IFS(A2,A2,B2,B2)
请注意,
IFS
仅适用于 Office 2019 及更高版本。

A - B(仅限 A):

=IF(NOT(IFNA(MATCH(A2,$B$2:$B$42,0),FALSE)),IF(A2,A2,""),"")

B - A(仅在 B 中):

=IF(NOT(IFNA(MATCH(B2,$A$2:$A$42,0),FALSE)),IF(B2,B2,""),"")
(交换字母)


3
投票

仅靠 Excel 似乎无法完成这项工作。但是,有可用的加载项。您可能想测试免费开源的 Power Analytics for Excel。它带有一些完全符合您要求的功能:

Excel 365 中的用法

在 Excel 365 Power Analytics for Excel 中允许使用动态数组。此功能仅包含在 Excel 365 中,在 Excel 2019、2016 等中不可用。

在下面的示例中,我们只需将 =PA_Sets_And(A2:A11;B2:B6) 写入单个单元格 D2,然后 - 就像魔术一样 - 公式扩展到所需的三行长度。

Excel 2019、2016、...中的用法

这里我们使用 PA_Sets_And 方法来查找单元格 (B2) 是否包含在整个集合的范围 (A2:A11) 中。不如 Excel 365 酷,但比 VLOOKUP 好一点:-)


2
投票

Microsoft Excel 不处理内置的集合运算。但是您可以使用 MATCH 函数和 错误处理通过 VBA 进行模拟。

这是对我有用的代码(我假设您的标题位于第一行):

Sub set_operations()
    Dim i, j, rangeA, rangeB, rowC, rowD, rowE, rowF As Long
    Dim test1, test2 As Boolean

    rangeA = ActiveSheet.Range("A" & CStr(ActiveSheet.Rows.Count)).End(xlUp).Row()
    rangeB = ActiveSheet.Range("B" & CStr(ActiveSheet.Rows.Count)).End(xlUp).Row()
    rowC = 2
    rowD = 2
    rowE = 2
    rowF = 2
    test1 = False
    test2 = False
    test2 = False

    'A union B
    On Error GoTo errHandler1
    For i = 2 To rangeA
        If Application.Match(ActiveSheet.Cells(i, 1), ActiveSheet.Range("C:C"), 0) > 0 Then
            If test1 = True Then
                ActiveSheet.Cells(rowC, 3) = ActiveSheet.Cells(i, 1)
                rowC = rowC + 1
            End If
        End If
        test1 = False
    Next i
    For j = 2 To rangeB
        If Application.Match(ActiveSheet.Cells(j, 2), ActiveSheet.Range("C:C"), 0) > 0 Then
            If test1 = True Then
                ActiveSheet.Cells(rowC, 3) = ActiveSheet.Cells(j, 2)
                rowC = rowC + 1
            End If
        End If
        test1 = False
    Next j

    'A intersection B
    For i = 2 To rangeA
        On Error GoTo errHandler2
        If Application.Match(ActiveSheet.Cells(i, 1), ActiveSheet.Range("B:B"), 0) > 0 Then
            On Error GoTo errHandler1
            If Application.Match(ActiveSheet.Cells(i, 1), ActiveSheet.Range("D:D"), 0) > 0 Then
                If test1 = True And test2 = False Then
                    ActiveSheet.Cells(rowD, 4) = ActiveSheet.Cells(i, 1)
                    rowD = rowD + 1
                End If
            End If
        End If
        test1 = False
        test2 = False
    Next i

    'A minus B
    For i = 2 To rangeA
        On Error GoTo errHandler2
        If Application.Match(ActiveSheet.Cells(i, 1), ActiveSheet.Range("B:B"), 0) > 0 Then
            On Error GoTo errHandler1
            If Application.Match(ActiveSheet.Cells(i, 1), ActiveSheet.Range("E:E"), 0) > 0 Then
                If test1 = True And test2 = True Then
                    ActiveSheet.Cells(rowE, 5) = ActiveSheet.Cells(i, 1)
                    rowE = rowE + 1
                End If
            End If
        End If
        test1 = False
        test2 = False
    Next i

    'B minus A
    For i = 2 To rangeB
        On Error GoTo errHandler2
        If Application.Match(ActiveSheet.Cells(i, 2), ActiveSheet.Range("A:A"), 0) > 0 Then
            On Error GoTo errHandler1
            If Application.Match(ActiveSheet.Cells(i, 2), ActiveSheet.Range("F:F"), 0) > 0 Then
                If test1 = True And test2 = True Then
                    ActiveSheet.Cells(rowF, 6) = ActiveSheet.Cells(i, 2)
                    rowF = rowF + 1
                End If
            End If
        End If
        test1 = False
        test2 = False
    Next i


errHandler1:
    test1 = True
    Resume Next

errHandler2:
    test2 = True
    Resume Next
End Sub

0
投票

您可以简单地使用下面的公式来获得结果

=IF(下(A4)=下(B4),"",A4)


0
投票

我在几个层面上感到惊讶:
(1) 现在已经2020年了....Excel中仍然没有设置函数
(2) 得票最高的答案(从 2018 年开始)非常不切实际:在现实生活中,与另一个数据集相比,在缺少值的情况下插入空行的数据集并不整齐;这是该解决方案的前提。

最实用的解决方案(虽然仍然很尴尬;你听到我们了吗,微软???)是在数据透视表的帮助下解决:

  • 将列添加到集合 A,列名称为“set_name”,列中的所有值设置为“A” -> 数据透视输入 A
  • 将列添加到集合 B,列名称为“set_name”,列中的所有值设置为“B” -> 数据透视输入 B
  • 在数据透视输入 A 下复制数据透视输入 B(没有列名称;-))以形成联合范围 -> 联合范围
  • 从联合范围创建数据透视表
    --- “设置名称”用于形成数据透视表的列
    --- 枢轴函数设置为“count()”

结果是一种“单热编码”数据透视表,其中:

  • 第一列:A 和 B 的并集(也称为所有出现的值)
  • 第二列:1-值仅适用于集合 A 中出现的元素
    (警告:假设 A 只包含唯一元素。否则,
    值 > 1 是可能的)
  • 第 3 列:仅对于集合 B 中出现的元素为 1 值
    (与 A 组相同的注意事项适用)
  • 总计列:两组中都存在显示“2”值的值

可以通过第 2 列(也称为“集合 A”)、第 3 列(又称为“集合 B”)和第 4 列(又称为“集合 A 和集合 B”)中的值,轻松地在不同集合和交集上过滤生成的数据透视表。


0
投票

RE:两个集合的交集

此解决方案适用于 Microsoft 365,并基于我在 另一篇文章中解释的方法。

  1. 我们找到哪个数组包含最多元素,以免错过任何一个。
  2. 我们利用 SCAN 公式,使用公式函数参数内的 XLOOKUP 作为 LAMBDA 的主体来查找两个数组之间的公共值。
  3. 每当没有找到查找数组和另一个数组的元素时,我们FILTER结果排除任何NA

对上述帖子代码的唯一修改是将LET的计算包装在UNIQUE公式中,以便我们得到一个实际的Set,如下所示:

=LAMBDA(array_a, array_b,
    LET(
        scanResult, IF(
            COUNTA(array_a) > COUNTA(array_b),
            SCAN(
                "",
                array_a,
                LAMBDA(accumulator, current, XLOOKUP(current, array_b, array_b))
            ),
            SCAN(
                "",
                array_b,
                LAMBDA(accumulator, current, XLOOKUP(current, array_a, array_a))
            )
        ),
        UNIQUE(FILTER(scanResult, NOT(ISNA(scanResult))))
    )
)
© www.soinside.com 2019 - 2024. All rights reserved.