Excel VBA 7.46字典+数字+窗体控件,跨工作表实现COUNTIF的功能
一起学习,一起进步~~
之前我们分享过一篇文章,就是通过字典+数组的方式来实现跨工作表求和的,在那一节的学习中,我们实现了count函数的跨工作表的一个求和的效果,后面有小伙伴表示,他碰到的场景不仅仅是求和,他希望能够得到了个类似countif函数的效果,跨工作表统计满足某条件的次数,这里我们划一下重点,次数,并不是总和,那么,我们要如何实现这样的功能呢?
代码区
我们还是使用相同的案列
我们当前依然需要针对这三个工作表的所有数据进行计算,我们现在希望通过类名,也就是姓名这一列来进行统计,语文成绩大于/等于/小于/介于
某一个值的次数,这个某小伙伴在课后提出来的要求,我们来实现他。
看看代码
因为今天我们要展示的场景比较的多,大于,小于,等于,还有介于,全部的代码展示出来太占篇幅了
我们就选择其中大于这个场景来展示代码,其他的场景也仅仅是修改下判断条件就可以了,大家可以自己按照需要编写代码
Sub dayu(s)
Dim rng As Range, trng As Range, schrng As Range, zd As Object, str$
Set zd = CreateObject("scripting.dictionary")
Set trng = Application.InputBox("请选择表头区域", "表头区域的确定", , , , , , 8)
TitleRow = trng.Rows.Count
Set rng = Application.InputBox("请选择类别区域", "类别区域的确定", , , , , , 8)
TargetCol = rng.Column
Set schrng = Application.InputBox("请选择数据区域", "数据区域的确定", , , , , , 8)
schrngCol = schrng.Column
For Each sth In Worksheets
l = sth.Cells(Rows.Count, TargetCol).End(xlUp).Row
For i = TitleRow + 1 To l
str = sth.Cells(i, TargetCol) & "-" & Cells(i, TargetCol + 1)
If zd.Exists(str) Then
If sth.Cells(i, schrngCol) > Int(s) Then
zd.Item(str) = zd.Item(str) + 1
End If
Else
If sth.Cells(i, schrngCol) > Int(s) Then
zd.Add str, 1
Else
zd.Add str, 0
End If
End If
Next i
Next sth
Worksheets.Add after:=Worksheets(Worksheets.Count)
ActiveSheet.Name = "大于"
CountNum = zd.Count
ActiveSheet.Range(Cells(1, 1), Cells(CountNum, 1)) = WorksheetFunction.Transpose(zd.keys())
ActiveSheet.Range(Cells(1, 2), Cells(CountNum, 2)) = WorksheetFunction.Transpose(zd.Items())
End Sub
仅仅针对大于条件的代码已经编写好了,我们先来看看代码的效果
当然本节提供的源码中已经涵盖了上面的4个场景的所有代码,并且为了提高通用性,我特意将这些条件放在一个窗体中来展示
对于窗体有兴趣大小伙伴们可以先研究下,我们后续还会单独针对窗体进行相关知识的分享
来看本节的代码执行效果
首先先会弹出一个窗体,让我们选择我们要执行的操作和相应的条件,假设这里我们选择要选择语文成绩大于110的情况
条件输入完毕之后,点击确定,开始进入对应的程序
这里我们先要依次选择对应的表头和类名所在的范围,然后我们来确定数据源的范围
这里的数据源就是指我们希望统计的学科所在的那一列,比方说我们想要统计语文成绩大于110的次数,那么我们就选择语文这一列
在选择范围的时候也要注意,这里一定要将表头那一列也选中
然后就可以等到程序运行的结果了
A22 的数据都是0?是我们统计错了吗?看下具体的数据,A22最高只有100,所以0是正确的的结果。
代码很好的执行了我们的需求
代码分析
实现了要求,那么我们就来啃一下今天的代码
Set zd = CreateObject("scripting.dictionary")
首先我们声明一个字典,这个字典就是来状态满足条件的格式的
然后我们要确定标头的区域
有了表头的区域之后,我们就需要得到表头总共有多少行,为什么要得到多少行呢?因为我们这里需要从表头的下一行开始进行遍历,
然后我们需要得到类别的区域
Set rng = Application.InputBox("请选择类别区域", "类别区域的确定", , , , , , 8)
不然我们怎么知道是按照什么来进行统计呢?
之后就是要得到数据区域
Set schrng = Application.InputBox("请选择数据区域", "数据区域的确定", , , , , , 8)
这个数据源就是我们要进行判断的那一列,比方说案例中我们判断的是语文成绩,所以这里我们就选择语文所在的列
For Each sth In Worksheets
l = sth.Cells(Rows.Count, TargetCol).End(xlUp).Row
For i = TitleRow + 1 To l
str = sth.Cells(i, TargetCol) & "-" & Cells(i, TargetCol + 1)
If zd.Exists(str) Then
If sth.Cells(i, schrngCol) > Int(s) Then
zd.Item(str) = zd.Item(str) + 1
End If
Else
If sth.Cells(i, schrngCol) > Int(s) Then
zd.Add str, 1
Else
zd.Add str, 0
End If
End If
Next i
Next sth
这一段就是我们之前学习的利用字段来循环判断的过程中,不过这里我们要注意的时候,我们这里要字典只需要一个值就可以了,一个是字典名称,一个就是字典的值,这个值就是满足条件的格式
当条件不存在的时候,我们这里要细分一下,如果满足条件,就是
zd.Add str, 1
不满足条件的话,就是
zd.Add str, 0
为什么这样呢?我们来试想下,满足条件就是记录为1,代表他第一次是满足条件的,如果第一次都不满足条件,我们不能忽略,要等级为0,证明第一次判断的时候他也不满足条件,后续判断的时候要在0的基础上增加,我们不满足条件就直接忽略的话,最终的结果是没有这个值的,比方说上面案例中的A22
如果我们不登记的话,就会变成不存在这个数据,那么到底这几个数不存在还是结果为0 ?这就不得而知了,所以这里要注意
具体的循环比较的过程,相信大家有了前面的基础,这里就很简单理解了。窗体的构造我们后面在深入学习,这里就不做深究了。
================================
好了,明晚21:00,准时再见!