Excel精英培训网

 找回密码
 注册
数据透视表40+个常用小技巧,让你一次学会!
楼主: 张雄友

[已解决]不放回抽取

[复制链接]
 楼主| 发表于 2015-10-18 17:47 | 显示全部楼层
金樽空对月 发表于 2015-10-18 15:28
这个速度的问题,前两天我帮别人处理过一次,刚开始他的代码是用单元格循环来的,我让它弄成数组,但他上 ...

如:
If gs = "" Then
Exit Sub
End If

我觉得下面的方法比上面的要提速:

If gs = "" Then Exit Sub

三句用一句来表达。

评分

参与人数 1 +1 收起 理由
金樽空对月 + 1 赞一个!

查看全部评分

excel精英培训的微信平台,每天都会发送excel学习教程和资料。扫一扫明天就可以收到新教程
回复

使用道具 举报

发表于 2015-10-18 19:56 | 显示全部楼层
张雄友 发表于 2015-10-18 17:47
如:
If gs = "" Then
Exit Sub

嗯,感谢分享。
回复

使用道具 举报

发表于 2015-10-18 19:58 | 显示全部楼层
  1. Public arr(), drr(), cs, sx
  2. Sub 抽奖()
  3. cs = cs + 1
  4. If cs > 1 Then
  5. GoTo zd
  6. End If
  7. r = Application.CountA(Sheet1.Range("a1:a1048576")) - 1
  8. drr = Sheet1.Range("a1:e" & r + 1)
  9. ReDim arr(1 To r)
  10. For k = 1 To r
  11. arr(k) = k + 1
  12. Next
  13. sx = r
  14. zd:

  15. tz:
  16. gs = InputBox("请输入抽取个数:" & "还剩" & sx & "个")
  17. If gs = "" Then
  18. Exit Sub
  19. End If
  20. If Val(gs) > sx Then
  21. MsgBox "抽取个数大于剩余个数,请调整抽取个数!"
  22. GoTo tz
  23. End If
  24. ReDim brr(1 To gs)
  25. For n = 1 To gs
  26. x = Int(Rnd() * (sx - n + 1)) + 1
  27. brr(n) = arr(x)
  28. arr(x) = arr(sx - n + 1)
  29. Next
  30. ReDim crr(1 To gs, 1 To 5)
  31. For m = 1 To gs
  32. crr(m, 1) = drr(brr(m), 1)
  33. crr(m, 2) = drr(brr(m), 2)
  34. crr(m, 3) = drr(brr(m), 3)
  35. crr(m, 4) = drr(brr(m), 4)
  36. crr(m, 5) = drr(brr(m), 5)
  37. Next
  38. wz = InputBox("请选择输出单元格如 F2")
  39. Sheet1.Range(wz).Resize(gs, 1).NumberFormatLocal = "@"
  40. Sheet1.Range(wz).Offset(0, 2).Resize(gs, 1).NumberFormatLocal = "yyyy-mm-dd"
  41. Sheet1.Range(wz).Resize(gs, 5) = crr
  42. sx = sx - gs
  43. End Sub

  44. Sub 清零()
  45. sx = 0
  46. cs = 0
  47. Erase arr()
  48. End Sub
复制代码
回复

使用道具 举报

发表于 2015-10-18 20:18 | 显示全部楼层
张雄友 发表于 2015-10-18 14:50
链接找不到东西,上代码即可。

我也是初学者,我的体会是对于工作表而言,尽量少进行读写操作,必要时整体赋值,数据的运算尽量在内存中进行,还有就是循环不能嵌套太多层。
回复

使用道具 举报

 楼主| 发表于 2015-10-18 20:39 | 显示全部楼层
循环不能嵌套太多层,这是提速的根本办法。
回复

使用道具 举报

发表于 2015-10-18 21:02 | 显示全部楼层
也写了一个,请参考一下。
  1. Sub Ax()
  2.     Dim Arr, Brr, Dic, D1, Cq, Wz As Range, Col, Crr
  3.     Arr = Range("a7:b" & Cells(Rows.Count, 1).End(3).Row)
  4.     Cq = Application.InputBox("请指定抽取人数", "设置", 20, , , , , 1)
  5.     Set Wz = Application.InputBox("请指定保存位置", "设置", , , , , , 8)
  6.     Set Dic = CreateObject("Scripting.Dictionary")
  7.     Set D1 = CreateObject("Scripting.Dictionary")
  8.     ReDim Crr(1 To Cq, 1 To 2)
  9.     Col = Columns.Count - 1
  10.     t = Timer
  11.     ''将原始数据,装进字典
  12.     For i = 1 To UBound(Arr)
  13.         Dic(Arr(i, 1)) = Arr(i, 2)
  14.     Next
  15.     If Cells(2, Col) <> "" Then
  16.         Brr = Cells(2, Col).CurrentRegion
  17.         For i = 1 To UBound(Brr)
  18.             Dic.Remove (Brr(i, 1))  '去除已经抽取过的数据
  19.         Next
  20.     End If
  21.     If Dic.Count = 0 Then           '如果全抽空,清空缓冲区
  22.         If MsgBox("数据已经抽空,请重新开始", vbYesNo, "提示") Then
  23.             Cells(2, Col).CurrentRegion.ClearContents
  24.         End If
  25.     End If
  26.     On Error Resume Next
  27.     Randomize
  28.     If Dic.Count > Cq Then      '单组抽取数量小于可抽取数量时,随机抽取
  29.         Do While js < Cq
  30.             n = Int(Rnd() * (Dic.Count - 1)) + 1
  31.             If Not D1.exists(Dic.keys()(n)) Then
  32.                 js = js + 1
  33.                 D1(Dic.keys()(n)) = Dic.items()(n)
  34.             End If
  35.         Loop
  36.         For i = 0 To D1.Count - 1
  37.             Crr(i + 1, 1) = D1.keys()(i)
  38.             Crr(i + 1, 2) = D1.items()(i)
  39.         Next
  40.     Else
  41.         For i = 0 To Dic.Count - 1          '单组抽取数量大于可用抽取数量时,
  42.             Crr(i + 1, 1) = Dic.keys()(i)
  43.             Crr(i + 1, 2) = Dic.items()(i)
  44.         Next
  45.     End If
  46.     Wz.Resize(UBound(Crr), 2) = Crr
  47.     Cells(1, Col).Resize(UBound(Crr), 2).Offset(Cells(Rows.Count, Col).End(3).Row) = Crr
  48.     MsgBox Format(Timer - t, "0.00") & "秒"
  49. End Sub
复制代码
不放回抽取.zip (33.45 KB, 下载次数: 5)
回复

使用道具 举报

 楼主| 发表于 2015-10-18 22:17 | 显示全部楼层
lmze2000 发表于 2015-10-18 21:02
也写了一个,请参考一下。

    Crr(i + 1, 1) = D1.keys()(i)
            Crr(i + 1, 2) = D1.items()(i)

根据我对字典的了解,上代码只适合二列的数据(一个key,一个item)抽取,像11楼多列数据如5列,好像不能实现对吗?请不要怪我无知。
回复

使用道具 举报

发表于 2015-10-19 07:19 | 显示全部楼层
张雄友 发表于 2015-10-18 22:17
Crr(i + 1, 1) = D1.keys()(i)
            Crr(i + 1, 2) = D1.items()(i)

只是针对你发的那个问题,11楼的,没有看见是什么样子的结构,如果保证只有一个关键字,后面的都是附属字段,都没有问题,不过即便有2个或者多个关键字,道理也应该是相通的。

评分

参与人数 1 +9 收起 理由
张雄友 + 9 赞一个!

查看全部评分

回复

使用道具 举报

发表于 2015-10-19 07:29 | 显示全部楼层
张雄友 发表于 2015-10-18 22:17
Crr(i + 1, 1) = D1.keys()(i)
            Crr(i + 1, 2) = D1.items()(i)

下载看了你的11楼附件了,和正常的没有什么不同啊,字典是有二个属性keys/items,items可以是单个也可以是多个字段的组合呀。

比如:

编号体重公斤入厂日期工号唯一血液
00001312015-10-17AC1G
00002292015-10-18AC2K
00003392015-10-19AC3J
00004712015-10-20AC4E
00005942015-10-21AC5J

这是你的数据,,,如果你想用工号唯一这个做key,那么其它的4项就可以作为item
  1. Sub Ax()
  2.     Dim Arr, Dic
  3.     Set Dic = CreateObject("Scripting.Dictionary")
  4.     Arr = [a6].CurrentRegion
  5.     For i = 1 To UBound(Arr)
  6.         bz = Arr(i, 1) & "*" & Arr(i, 2) & "*" & Arr(i, 3) & "*" & Arr(i, 5)
  7.         Dic(Arr(i, 4)) = bz
  8.     Next
  9. End Sub
复制代码
之后的实际情况就是key AC1对应的item就是 "00001*31*2015-10-17*G"
在使用的时候,split就OK了。
回复

使用道具 举报

 楼主| 发表于 2015-10-19 07:43 | 显示全部楼层
lmze2000 发表于 2015-10-19 07:29
下载看了你的11楼附件了,和正常的没有什么不同啊,字典是有二个属性keys/items,items可以是单个也可以是 ...

不太明白,如改成这样?

二维数组不放回抽取是否成功.rar

1.72 MB, 下载次数: 6

回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-5-4 12:36 , Processed in 0.440252 second(s), 15 queries , Gzip On, Yac On.

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

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