Excel精英培训网

 找回密码
 注册
数据透视表40+个常用小技巧,让你一次学会!
查看: 4707|回复: 22

[已解决]这类循环方式是针对什么问题的

[复制链接]
发表于 2012-11-9 22:07 | 显示全部楼层 |阅读模式
Sub test()
    Dim f(1 To 24)
    For i = 11 To 38
        If i Mod 10 > 0 And i Mod 10 < 9 Then j = j + 1: f(j) = i
    Next
   
    For a = 1 To 8
        For b = a + 1 To 9
            For c = b + 1 To 10
                For d = c + 1 To 11
                    For e = d + 1 To 12
    t = f(a) & ";" & f(b) & ";" & f(c) & ";" & f(d) & ";" & f(e)
                    
    Next e, d, c, b, a
End Sub
这是:http://www.excelpx.com/thread-221459-2-1.html 20# 香川老师的代码
原帖只看规则,我就头晕了。


因为,以前也看到过这样循环,一直纳闷为什么要这样循环。
所以,这里我想认识这种循环方式,是专门解决什么样的问题的?我猜是专门的,好像公式一样,一定有啥原因吧 ....
可否举一个简单的小例子。这样,好从容易懂的小例子里去体会。谢谢!


PS:本帖我不希望设最佳,只想多认识一点知识


最佳答案
2012-11-11 14:21
呵呵,我自己来回答。

1. 这样的代码作用,是最基本的,通过循环产生不重复组合的【组合代码】
结果是: =combin(m,n) 的所有组合解。

2. 用VBA代码生成组合结果,方法有很多。
a. 本例所示,是最基本的,或称最标准的数组循环方法。

优点是:
计算速度最快。(其他任何方法,都不可能比它更快!)
第2个优点是,非常直观,便于新手理解和模仿。

缺点是:
通用性不强。即,如果m,n参数需要改变,那么代码就需要重新编写……

但是,这个问题,我有自己的独门暗器解决。
即,我另做了一个生成组合代码的VBA
  1. Sub 自动生成组合代码()
  2.    
  3.     m = Val(InputBox("组合对象个数 m =", "生成组合代码", 10))
  4.     If m = 0 Then Exit Sub
  5.     n = Val(InputBox("抽取个数 n =", "生成组合代码", 3))
  6.     If n = 0 Then Exit Sub
  7.     AC = WorksheetFunction.Combin(m, n)
  8.     MsgBox "组合结果总数 = " & AC
  9.    
  10.     tn = "AutoCombin_" & Format(Date, "yymmdd_") & Format(Time, "hhmm_") & "Macro"
  11.     '本组合代码名称为: 【AutoCombin_yymmdd_hhmm_Macro】,确保每次名称不同
  12.     s = s & "Sub " & tn & "()" & Chr(10) & Chr(10)
  13.     s = s & "tms = Timer" & Chr(10)
  14.     s = s & "m = " & m & " : n = " & n & Chr(10)
  15.     s = s & "ReDim jg(1 To " & AC & ", 0 To n)" & Chr(10)
  16.    
  17.     T1 = "Dim i1%"
  18.     For i = 2 To n
  19.         T1 = T1 & ", i" & i & "%"
  20.     Next
  21.     s = s & T1 & Chr(10)
  22.    
  23.     s = s & "For i1 = 1 To " & m - n + 1 & Chr(10)
  24.    
  25.     T2 = " jg(i, 0) = i1"
  26.     T3 = " jg(i, 1) = i1"
  27.     T4 = "next i" & n
  28.     For i = 2 To n
  29.         s = s & "For i" & i & " = i" & i - 1 & " + 1 To " & m - n + i & Chr(10)
  30.         T2 = T2 & " & "","" & i" & i
  31.         T3 = T3 & " : jg(i, " & i & ") = i" & i
  32.         T4 = T4 & ", i" & n - i + 1
  33.     Next
  34.     s = s & " i = i + 1" & Chr(10)
  35.     s = s & T2 & Chr(10)
  36.     s = s & T3 & Chr(10)
  37.     s = s & T4 & Chr(10)
  38.    
  39.     s = s & "[a1].CurrentRegion.Clear: [a1].Resize(i, n + 1) = jg" & Chr(10)
  40.     s = s & "[a1].Resize(, n + 1).EntireColumn.AutoFit" & Chr(10)
  41.     s = s & "Msgbox i & vbcr & Format(Timer - tms ,""0.000s"")" & Chr(10) & Chr(10)
  42.     s = s & "End Sub" & Chr(10)
  43.    
  44.     '以上为止,自动生成了能够计算combin(m,n)组合的标准循环代码 s
  45.     [a1] = s '输出代码到A1单元格中(代码行之间有换行符)

  46.     ' 如果只需要添加模块到当前工作簿,但不需要自动执行新生成的代码,则:
  47.     Set t = ActiveWorkbook.VBProject.VBComponents.Add(1) '在当前工作簿文件中自动添加模块
  48.     t.CodeModule.AddFromString s '在此新添加的模块中写入此代码
  49.     Exit Sub
  50.     '如果要立即自动执行此组合代码,那么:
  51.     Set t = ThisWorkbook.VBProject.VBComponents.Add(1) '在本代码所属工作簿文件中自动添加模块,
  52.     t.CodeModule.AddFromString s '在此新添加的模块中写入此代码
  53.     Application.Run tn '自动执行此代码
  54.     ThisWorkbook.VBProject.VBComponents.Remove t '执行完之后立即删掉此代码模块→不需要时注释掉
  55.    
  56. End Sub
复制代码
执行上述代码,就能自动生成标准的,生成combin(m,n)解的代码。

例如,执行代码,输入m=5,n=3参数后,自动在当前工作薄内生成一个模块,里面有代码:

Sub AutoCombin_121111_1419_Macro()

tms = Timer
m = 5: n = 3
ReDim jg(1 To 10, 0 To n)
Dim i1%, i2%, i3%
For i1 = 1 To 3
For i2 = i1 + 1 To 4
For i3 = i2 + 1 To 5
i = i + 1
jg(i, 0) = i1 & "," & i2 & "," & i3
jg(i, 1) = i1: jg(i, 2) = i2: jg(i, 3) = i3
Next i3, i2, i1
[a1].CurrentRegion.Clear: [a1].Resize(i, n + 1) = jg
[a1].Resize(, n + 1).EntireColumn.AutoFit
MsgBox i & vbCr & Format(Timer - tms, "0.000s")

End Sub
excel精英培训的微信平台,每天都会发送excel学习教程和资料。扫一扫明天就可以收到新教程
发表于 2012-11-9 23:09 | 显示全部楼层
绿色字体部份吗?
因为要5个元素组合,就须建立5次循环
所有的循环起始点结束点都比上一个循环加1,避免重复
回复

使用道具 举报

 楼主| 发表于 2012-11-9 23:42 | 显示全部楼层
chin15 发表于 2012-11-9 23:09
绿色字体部份吗?
因为要5个元素组合,就须建立5次循环
所有的循环起始点结束点都比上一个循环加1,避免重 ...

谢谢chin15!

是的,指绿色部分。即循环初值不同。

比如如用这种循环(绿色),可否编造一个循环体?使代码的效果,可能为我们解决某种常见问题。
这样,好从例子中来比较,初值这么改的好处。
回复

使用道具 举报

发表于 2012-11-9 23:51 | 显示全部楼层
应该就是个常见的组合问题(一般是使用递归来做)吧?你把数组改成连续的A、B、C、D……,再运行代码,把结果全写进表格中,就看得出规律了,很直观的
回复

使用道具 举报

发表于 2012-11-9 23:55 | 显示全部楼层
这是为了在同一组数据源中循环组合避免重复才这样设的呀!
如有一组数字1,2,3,4,5,
做三个数字的组合
第一个循环初始值1,第二个循环初始值2,第三个循环初始值3
那第一个得到的组合就是1,2,3
下一个得到的是1,2,4
若不把初始值加1,得到的是1,1,1~1,1,2~1,1,3.........
回复

使用道具 举报

 楼主| 发表于 2012-11-9 23:58 | 显示全部楼层
本帖最后由 爱疯 于 2012-11-10 00:03 编辑
上清宫主 发表于 2012-11-9 23:51
应该就是个常见的组合问题(一般是使用递归来做)吧?你把数组改成连续的A、B、C、D……,再运行代码,把结 ...


谢谢上清!
能否举一个小例子,因为用1楼的代码不好对比效果。简单点。。。。啊

就像A,B,C,D四个字符,取其中2个,列举组合。是这种问题?就举这个吧 。。。就是这种格式循环做的么?

返回:
AB
AC
AD
....


输出怎么方便,怎么设置都可以。


回复

使用道具 举报

 楼主| 发表于 2012-11-10 00:01 | 显示全部楼层
chin15 发表于 2012-11-9 23:55
这是为了在同一组数据源中循环组合避免重复才这样设的呀!
如有一组数字1,2,3,4,5,
做三个数字的组合

谢谢!
方便的话,用6#的问题写个吧,好好学习一下,我老是不会做这类问题{:021:}
回复

使用道具 举报

发表于 2012-11-10 00:05 | 显示全部楼层
对,就是这个意思
从m个元素中取n个(n<=m)的组合,早就有非常成熟的递归代码,要以从网上去找找。
象群子这样做成循环,执行效率比递归高,可是,当n不定的,代码很难写(据说所有的递归都可写成循环,但我写不出来
回复

使用道具 举报

 楼主| 发表于 2012-11-10 00:22 | 显示全部楼层
上清宫主 发表于 2012-11-10 00:05
对,就是这个意思
从m个元素中取n个(n

只想认识最简单的方法,不看效率,只求先能理解

是不是就是1#这种循环方式?
回复

使用道具 举报

 楼主| 发表于 2012-11-10 00:31 来自手机 | 显示全部楼层
太晚 了,各位也早点休息吧,明天再向各位学习啊!
回复

使用道具 举报

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

本版积分规则

小黑屋|手机版|Archiver|Excel精英培训 ( 豫ICP备11015029号 )

GMT+8, 2024-3-29 17:27 , Processed in 0.783547 second(s), 8 queries , Gzip On, Yac On.

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

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