集合示例

为了巩固本章所学,安排了3个与集合有关的示例,给出了Excel VBA和Python两个版本的代码。

集合示例1-统计参加兴趣班的所有同学

图9-5所示工作表中第1-2列列出了参加绘画班和钢琴班的学生名单,现在要求统计出参加了兴趣班的所有同学。

Document Image

图9-5 统计参加兴趣班的所有同学

把绘画班和钢琴班分别作为两个集合,则所求问题即是求两个集合的并集。

【Excel VBA】

示例文件的存放路径为Samples\ch09\Excel VBA\找出参加兴趣班的所有同学.xlsm。

code.vba
Sub Test()
  Dim intI As Integer
  Dim intR1 As Integer  '第1列数据个数
  Dim intR2 As Integer  '第2列数据个数
  Dim arr1(), arr2(), arr3()  '第1,2列数据,合并后数据
  Dim sht As Object
  Set sht = ActiveSheet

  '第1,2列数据个数
  intR1 = sht.Range("A1").End(xlDown).Row
  intR2 = sht.Range("B1").End(xlDown).Row
  '获取第1,2列数据,二维
  arr1 = sht.Range("A2:A" & CStr(intR1)).Value
  arr2 = sht.Range("B2:B" & CStr(intR2)).Value
  '第1,2列数据二维转一维
  arr1 = Application.WorksheetFunction.Transpose(arr1)
  arr2 = Application.WorksheetFunction.Transpose(arr2)
  '集合求并
  arr3 = Union(arr1, arr2)
  '输出合并后的结果
  sht.Range("D2").Resize(UBound(arr3) - LBound(arr3), 1).Value = _
            Application.WorksheetFunction.Transpose(arr3)
End Sub

运行程序,汇总结果如图9-5所示工作表中D列所示。

【Python】

本示例的数据文件存放路径为Samples\ch09\Python\找出参加兴趣班的所有同学.xlsx,py文件保存在相同目录下,文件名为sam09-01.py。

code.python
import xlwings as xw  #导入xlwings包
#从constants类中导入Direction
from xlwings.constants import Direction
import os  #导入os包
#获取本py文件的当前路径
root = os.getcwd()
#创建Excel应用,可见,没有工作簿
app=xw.App(visible=True, add_book=False)
#打开数据文件,可写
bk=app.books.open(fullname=root+\
    r'\找出参加兴趣班的所有同学.xlsx',read_only=False)
sht=bk.sheets(1)  #获取第1个工作表
#工作表中第1列数据最大行号
row_num_1=sht.api.Range('A1').End(Direction.xlDown).Row
#工作表中第2列数据最大行号
row_num_2=sht.api.Range('B1').End(Direction.xlDown).Row
#第1列数据
data_1=sht.range('A2:A'+str(row_num_1)).value
#第2列数据
data_2=sht.range('B2:B'+str(row_num_2)).value
#列表转集合
set_1=set(data_1)
set_2=set(data_2)
#集合求并
set_3=set_1.union(set_2)
#输出并集,即所有参加兴趣班的同学
sht.range('D2').options(transpose=True).value=list(set_3)

运行脚本,汇总结果如图9-5所示工作表中D列所示。

集合示例2-跨表去重

图9-6中上面两个图分别显示了工作簿中的两个工作表,表中都是部门人员信息。现在要求从第1个表中去掉与第2个表中重复的数据行。

Document Image

图9-6 表1去掉与表2中重复的数据行

把两个工作表的工号列数据分别作为两个集合,则所求问题即是求这两个集合之间的差集,然后将差集中工号对应的数据行复制到第3个工作表中。

【Excel VBA】

示例文件的存放路径为Samples\ch09\Excel VBA\身份证号-跨表去重.xlsm。

code.vba
Sub Test()
  Dim intI As Integer
  Dim intN As Integer
  Dim intR1 As Integer  '第1个表的数据个数
  Dim intR2 As Integer  '第2个表的数据个数
  Dim arr1(), arr2()  '第1,2个表的数据
  Dim arr3()  '差集运算结果

  '第1,2个表的数据个数
  intR1 = Sheets(1).Range("A1").End(xlDown).Row
  intR2 = Sheets(2).Range("A1").End(xlDown).Row
  '获取第1,2个表的工号数据,二维
  arr1 = Sheets(1).Range("A2:A" & CStr(intR1)).Value
  arr2 = Sheets(2).Range("A2:A" & CStr(intR2)).Value
  '第1,2个表的工号数据二维转一维
  arr1 = Application.WorksheetFunction.Transpose(arr1)
  arr2 = Application.WorksheetFunction.Transpose(arr2)
  '集合求差集,即获取第一个表中不包含第二个表中同学的同学
  arr3 = Difference(arr1, arr2)

  '在第三个表中输出结果
  Sheets(1).Rows(1).Copy Sheets(3).Rows(1)
  intN = 1
  '遍历第一个表第一列,如果工号在差集中存在
  '则复制该行数据并添加到第三个表后面
  For intI = LBound(arr1) To UBound(arr1)
    If InArr(arr1(intI), arr3) Then
      intN = intN + 1
      Sheets(1).Rows(intI + 1).Copy Sheets(3).Rows(intN)
    End If
  Next
  Sheets(3).Activate
End Sub
Function InArr(Val, arr()) As Boolean
  '判断Val在数组arr中是否存在
  Dim intI As Integer
  InArr = False
  For intI = LBound(arr) To UBound(arr)
    If Val = arr(intI) Then
      InArr = True
      Exit For
    End If
  Next
End Function

运行程序,所求结果如图9-6中下图所示。

【Python】

本示例的数据文件存放路径为Samples\ch09\Python\身份证号-跨表去重.xlsx,py文件保存在相同目录下,文件名为sam09-02.py。

code.python
import xlwings as xw  #导入xlwings包
#从constants类中导入Direction
from xlwings.constants import Direction
import os  #导入os包
#获取本py文件的当前路径
root = os.getcwd()
#创建Excel应用,可见,没有工作簿
app=xw.App(visible=True, add_book=False)
#打开数据文件,可写
bk=app.books.open(fullname=root+\
    r'\身份证号-跨表去重.xlsx',read_only=False)
sht1=bk.sheets(1)  #获取第1个工作表
sht2=bk.sheets(2)  #获取第2个工作表
sht3=bk.sheets(3)
#工作表1中A列数据最大行号
row_num_1=sht1.api.Range('A1').End(Direction.xlDown).Row
#工作表2中A列数据最大行号
row_num_2=sht2.api.Range('A1').End(Direction.xlDown).Row
#表1中A列数据
data_1=sht1.range('A2:A'+str(row_num_1)).value
#表2中A列数据
data_2=sht2.range('A2:A'+str(row_num_2)).value
#列表转集合
set_1=set(data_1)
set_2=set(data_2)
#集合差运算
set_3=set_1.difference(set_2)
#复制表头
sht1.api.Rows(1).Copy()  #复制表1第1行
sht3.api.Activate()  #跨表复制,需要先激活目标工作表
sht3.api.Range('A1').Select()  #选择粘贴的位置
sht3.api.Paste()  #粘贴
#遍历表1中A列,如果当前工号在集合3中存在
#则行数据复制到表3
n=1  #记录复制数据的行数
for i in range(2,row_num_1):
    if sht1.cells(i,1).value in set_3:
        n+=1
        sht1.api.Rows(i).Copy()  #整行复制
        sht3.api.Activate()
        sht3.api.Rows(n).Select()
        sht3.api.Paste()

运行脚本,所求结果如图9-6中下图所示。

集合示例3-找出报和没有报两个兴趣班的同学

图9-7所示工作表中第1-2列列出了参加绘画班和钢琴班的学生名单,现在要求统计出两个兴趣班都报了的同学和只报了一个班的同学。

Document Image

图9-7 汇总报和没有报两个兴趣班的学生名单

把绘画班和钢琴班分别作为两个集合,则汇总两个兴趣班都报了的同学是求两个集合的交集;汇总只报了一个班的同学是求两个集合的对称差集。

【Excel VBA】

示例文件的存放路径为Samples\ch09\Excel VBA\找出报和没有报两个兴趣班的同学.xlsm。

code.vba
Sub Test()
  Dim intI As Integer
  Dim intR1 As Integer  '第1列数据个数
  Dim intR2 As Integer  '第2列数据个数
  Dim arr1(), arr2()  '第1,2列数据
  Dim arr3(), arr4()  '交运算和对称差集运算结果
  Dim sht As Object
  Set sht = ActiveSheet

  '第1,2列数据个数
  intR1 = sht.Range("A1").End(xlDown).Row
  intR2 = sht.Range("B1").End(xlDown).Row
  '获取第1,2列数据,二维
  arr1 = sht.Range("A2:A" & CStr(intR1)).Value
  arr2 = sht.Range("B2:B" & CStr(intR2)).Value交
  '第1,2列数据二维转一维
  arr1 = Application.WorksheetFunction.Transpose(arr1)
  arr2 = Application.WorksheetFunction.Transpose(arr2)
  '集合求交,即两个班都报了的同学
  arr3 = Intersection(arr1, arr2)
  '集合求对称差集,即只报一个班的同学
  arr4 = SymDif(arr1, arr2)
  '输出结果
  sht.Range("D2").Resize(UBound(arr3) - LBound(arr3) + 1, 1).Value = _
            Application.WorksheetFunction.Transpose(arr3)
  sht.Range("E2").Resize(UBound(arr4) - LBound(arr4) + 1, 1).Value = _
            Application.WorksheetFunction.Transpose(arr4)
End Sub

运行程序,统计结果如图9-7所示工作表中D列和E列所示。

【Python】

本示例的数据文件存放路径为Samples\ch09\Python\找出报和没有报两个兴趣班的同学.xlsx,py文件保存在相同目录下,文件名为sam09-03.py。

code.python
import xlwings as xw  #导入xlwings包
#从constants类中导入Direction
from xlwings.constants import Direction
import os  #导入os包
#获取本py文件的当前路径
root = os.getcwd()
#创建Excel应用,可见,没有工作簿
app=xw.App(visible=True, add_book=False)
#打开数据文件,可写
bk=app.books.open(fullname=root+\
    r'\找出报和没有报两个兴趣班的同学.xlsx',read_only=False)
sht=bk.sheets(1)  #获取第1个工作表
#工作表中第1列数据最大行号
row_num_1=sht.api.Range('A1').End(Direction.xlDown).Row
#工作表中第2列数据最大行号
row_num_2=sht.api.Range('B1').End(Direction.xlDown).Row
#第1列数据
data_1=sht.range('A2:A'+str(row_num_1)).value
#第2列数据
data_2=sht.range('B2:B'+str(row_num_2)).value
#列表转集合
set_1=set(data_1)
set_2=set(data_2)
#集合求交
set_3=set_1.intersection(set_2)
#集合求对称差集
set_4=set_1.symmetric_difference(set_2)
#输出交集,即参加了两个兴趣班的同学
sht.range('D2').options(transpose=True).value=list(set_3)
#输出对称差集,即只参加了一个兴趣班的同学
sht.range('E2').options(transpose=True).value=list(set_4)

运行脚本,统计结果如图9-7所示工作表中D列和E列所示。