找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
热搜: 活动 交友 discuz
宇哥帮你零基础建设外贸独立站
宇哥淘宝虚拟类目-付费微信群
宇哥闲鱼3个月陪跑课
Access数据库-零基础入门课程
Access数据库-自用软件开发课程
Access数据库-即学即用课程
Access数据库-进销存课程
Access数据库-VBA入门课程
Access数据库-陪跑课程
查看: 377|回复: 0

VBA模块实例:统计函数的制作和调用(基于Access)

[复制链接]

115

主题

15

回帖

633

积分

管理员

积分
633
发表于 2024-3-7 15:26:47 | 显示全部楼层 |阅读模式
在VB编程里,模块和子过程是非常重要的概念,把他俩用好了可以让VB\VBA代码变得井井有条、易于管理、易于复制。
本教程用VBA教大家做一个统计函数模块,其中包含9种统计计算:合计值、平均值、最大值、最小值、众数、中位数、方差、标准差、离散系数。做完模块之后,在Access数据库窗体中进行调用的完整过程,也会进行讲解。
通过本课的学习,老铁们可以零距离领略VB模块化开发的优点,理解面向对象编程的好处。
本课分为3个部分:
  • 模块和子过程的概念
  • 完整代码分享
  • 部分代码解释


学完本课做出的效果演示
1模块和子过程的概念
模块里一般放一些比较常用的、有自变量因变量的函数,函数就是我们中学学的y=f(x)之类的方程,可以导出导入方便使用,并像积木一样可以拆下来用在别的程序里,因此取名叫模块。


方程Function一般放在模块里
子过程就是从一段很长的代码中,把可能重复的部分,单独搞出来做一个部分,需要的时候再调用一下,能有效缩短代码行数,便于管理、便于修改、便于展示。
子过程和模块的界限在VBA里不是很严格,把子过程放在模块也是可以的,把函数方程放在过程里、不放模块里也一点问题没有。
当然不应用模块和子过程,对于VB编程来说也没什么问题。对于初学者来说(比如我),理解模块和函数确实要花一些时间,一开始上手编程,可能也不容易体会模块和子过程的好处。我是花了很久之后,才知道为什么要有模块和子过程这种东西。
这种不应用子过程,也不搞模块,一条道搞到底的编程,我如果没有理解错的话,学名应该叫做面向过程编程((Procedure Oriented Programming)。
面向过程编程本身没有什么问题。但如果能熟练应用模块和子过程,可以让VB使用者编程过程更加清楚、层次分明,便于修改,对此我深有体会。本文的案例,也会非常直观的告诉读者应用模块和子过程的好处。如果我没理解错的话,这种大量应用子过程和模块的编程,应该叫面向对象编程((Object Oriented Programming)。(如果我理解的不对,还请各位读者指正)


2 完整代码分享
9个常用的统计函数代码(封装在模块里)求平均值、最大值、最小值、求和的代码,比较简单。
  1. Function Average(a() As Integer) '求平均值
  2. For i = 0 To UBound(a)
  3.     s = s + a(i)
  4.     c = c + 1
  5. Next i
  6.     Average = s / c
  7. End Function

  8. Function sum(a() As Integer) '求和
  9. For i = 0 To UBound(a)
  10.     sum = sum + a(i)
  11. Next i
  12. End Function

  13. Function Max(a() As Integer)  '最大值
  14.     Max = a(0)
  15. For i = 0 To UBound(a)
  16.     If a(i) > Max Then Max = a(i)
  17. Next i
  18. End Function

  19. Function Min(a() As Integer) '最小值
  20.     Min = a(0)   
  21. For i = 0 To UBound(a)
  22.     If a(i) < Min Then Min = a(i)
  23. Next i
  24. End Function
复制代码

求中位数、方差、标准差、离散系数的代码,相对比较简单。
  1. Function Median(a() As Integer, n As Integer) '中位数
  2. If n Mod 2 = 1 Then
  3.     Median = a(n / 2)
  4. Else
  5.     Median = (a(n / 2) + a(n / 2 + 1)) / 2
  6. End If
  7. End Function

  8. Function Variance(a() As Integer) '方差
  9. For i = 0 To UBound(a)
  10.     s = s + (a(i) - Average(a)) ^ 2
  11. Next
  12.     Variance = s / (UBound(a) + 1)
  13. End Function

  14. Function StandardDeviation(a() As Integer) '标准差
  15. For i = 0 To UBound(a)
  16.     s = s + (a(i) - Average(a)) ^ 2
  17. Next
  18.     StandardDeviation = (s / (UBound(a) + 1)) ^ (1 / 2)
  19. End Function

  20. Function DiscreteCoefficient(a() As Integer) '离散系数
  21. For i = 0 To UBound(a)
  22.     s = s + (a(i) - Average(a)) ^ 2
  23. Next
  24.     DiscreteCoefficient = ((s / (UBound(a) + 1)) ^ (1 / 2)) / Average(a)
  25. End Function
复制代码

最难的就是众数的代码,因为众数不一定只有一个,编程非常复杂,具体原理本课程暂不介绍。
  1. Function Mode(a() As Integer) '众数
  2. Dim b, c(), f(), i, j, k, x()

  3.     k = UBound(a)
  4.    
  5. ReDim c(k), f(k)

  6. For i = 0 To k - 1
  7.     If f(i) = 0 Then
  8.         c(i) = 1
  9.     For j = i + 1 To k
  10.         If a(j) = a(i) Then
  11.             c(i) = c(i) + 1
  12.             f(j) = 1
  13.         End If
  14.     Next
  15.     End If
  16. Next

  17. If f(i) = 0 Then c(i) = 1
  18.     b = 1
  19.    
  20. For i = 0 To k
  21.     If c(i) > b Then b = c(i)
  22. Next

  23. '若所有数据都是众数,则没有众数
  24. For i = 0 To k
  25.     If c(i) <> b And c(i) <> 0 Then Exit For
  26. Next

  27. If i = k + 1 Then
  28. ReDim x(0)
  29.     x(0) = "没有众数"
  30.     Mode = x
  31. Exit Function
  32. End If

  33. '找出所有众数
  34.     j = 0
  35. For i = 0 To k
  36.     If c(i) = b Then
  37.     ReDim Preserve x(j)
  38.         x(j) = a(i)
  39.         j = j + 1
  40.     End If
  41. Next
  42.     Mode = x
  43. End Function
复制代码

调用代码
本案例利用Access数据库的窗体功能,先生成了25个随机数并进行排序,然后再对这25个数进行以上的统计操作。
生成不重复数的子过程如下:
  1. Public Sub NoRepeatedNumbers(a) '生成25个不重复的数
  2. For i = 0 To 24
  3.     a(i) = Int(30 * Rnd + 1)
  4.         For j = 0 To i - 1 '这段是防止重复的代码
  5.             If a(i) = a(j) Then '如果重复了再次选择
  6.                 i = i - 1
  7.             End If
  8.        Next j
  9.    Next i
  10. End Sub
复制代码

子过程跟函数不一样,没有返回值,而函数有x也必须有个结果y。
生成重复数的子过程如下:
  1. Public Sub RepeatedNumbers(a) ''生成25个可能有重复的数
  2. For i = 0 To 24
  3.     a(i) = Int(30 * Rnd + 1)
  4.    Next i
  5. End Sub
复制代码

排序利用的是冒泡算法:
  1. Public Sub Bubble(a) '冒泡算法
  2. Dim i, j As Integer
  3. For i = 0 To 24
  4.     For j = i + 1 To 24
  5.         If a(i) > a(j) Then
  6.             t = a(i) 't作为中间变量,冒泡算法常见
  7.             a(i) = a(j)
  8.             a(j) = t
  9.         End If
  10.     Next j
  11. Next i
  12. End Sub
复制代码

Access窗体利用按钮控件,进行自动的计算,并将计算结果输出至从Text1到Text10共10个文本框中,其中Text1是生成的25个随机数(已经排好序),Text2-Text10是统计函数的直接调用,非常简便,其中数组a是变量,输出结果直接显示在Text1中。
  1. Option Compare Database

  2. Dim a(24) As Integer '数组一共25个数字
  3. Dim i As Integer
  4. Dim j As Integer
  5. Dim tempStr As String '中间变量,用于数列分行
  6. Dim t As Double '中间变量,排序用

  7. Private Sub Command1_Click()
  8.    
  9.     Text1 = ""
  10.     tempStr = " "
  11.    
  12. Call NoRepeatedNumbers(a)
  13. '下面这段是生成不重复的25个数字,从1-30的数字里选择
  14.    
  15. Call Bubble(a) '这段是排序,运用冒泡算法

  16. '这段是在文本框里生成25个数字
  17. For i = 0 To 24
  18.     Text1 = Text1 + tempStr + CStr(a(i)) 'CStr转换成字符串
  19.     If (i + 1) Mod 5 = 0 Then
  20.         tempStr = Chr(13) + Chr(10) + " " '换行
  21.     Else
  22.         tempStr = " "
  23.     End If
  24. Next i

  25. '进行统计计算
  26. Text2 = Average(a)
  27. Text3 = sum(a)
  28. Text4 = Max(a)
  29. Text5 = Min(a)
  30. Text6 = Median(a, 25)
  31. Text7 = Mode(a)
  32. Text8 = Variance(a)
  33. Text9 = StandardDeviation(a)
  34. Text10 = DiscreteCoefficient(a)

  35. End Sub
复制代码

注意两个Call,是调用子过程“冒泡算法”和“生成25个数”,这种调用的优点非常明显:
  • 代码比较有层次感,不会挤在一起,防止误操作。
  • 可以重复调用,避免重复输入,防止误操作。
比如本案例,有两个按钮,第二个按钮生成的是可能重复的25个数字(去掉了防止重复的代码)
然后第二个按钮代码如下,和上一段代码很类似,只改动了第二个Call召唤的子过程。
  1. Private Sub Command2_Click()
  2.    
  3.     Text1 = ""
  4.     tempStr = " "
  5.    
  6. Call RepeatedNumbers(a) '是生成可能重复的25个数字,从1-30的数字里选择
  7.    
  8. Call Bubble(a) '这段是排序,运用冒泡算法

  9. '这段是在文本框里生成25个数字
  10. For i = 0 To 24
  11.         Text1 = Text1 + tempStr + CStr(a(i)) 'CStr转换成字符串
  12.     If (i + 1) Mod 5 = 0 Then
  13.         tempStr = Chr(13) + Chr(10) + " " '换行
  14.     Else
  15.         tempStr = " "
  16.     End If
  17. Next i

  18. '进行统计计算
  19. Text2 = Average(a)
  20. Text3 = sum(a)
  21. Text4 = Max(a)
  22. Text5 = Min(a)
  23. Text6 = Median(a, 25)
  24. Text7 = Mode(a)
  25. Text8 = Variance(a)
  26. Text9 = StandardDeviation(a)
  27. Text10 = DiscreteCoefficient(a)

  28. End Sub
复制代码

注意观察第6行。两个按钮的区别就是一个是“Call RepeatedNumbers(a)”,一个是“Call NoRepeatedNumbers(a)”。
3 部分代码讲解
9个常用的统计函数代码(封装在模块里)求平均值、最大值、最小值、求和的代码,比较简单。利用For循环遍历即可,求和操作:利用for循环,遍历数组从0一直到最大下标Ubound,将数组数字层层相加。求平均值操作:在求和的基础上除以数组总数量,每遍历一次,分母+1.求最大最小值:基本思想是把数组中的所有数字都和Max和Min比较一遍,Max和Min值取数组第一个数。这种方法只适合排序好的数组。
求中位数、方差、标准差、离散系数的代码编写思路:基本都是对照函数方程进行编写,有的计算平均数是调用了之前的函数代码。这些代码中蕴含的数学更多一些,也比代码本身重要。
调用代码
子过程的调用是采用Call语句。
函数的调用就是直接调用函数名称。
本章先讲到这里,VBA用函数编程的难度不高,但是代码的长度超出了我的想象,看来以后讲解还是以个案为主比较好。

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Access即学即用
access陪跑
access开发
Access零基础
Access进销存

QQ|小黑屋|宇哥编程论坛 ( 京ICP备2022024677号-2|京公网安备11011202100561号 )

GMT+8, 2024-12-23 07:32 , Processed in 0.093706 second(s), 22 queries .

Powered by 宇哥

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表