Foxtable(狐表)用户栏目专家坐堂 → 高效随机抽取少量和大量记录的方法


  共有4864人关注过本帖树形打印复制链接

主题:高效随机抽取少量和大量记录的方法

帅哥哟,离线,有人找我吗?
狐狸爸爸
  1楼 | 信息 | 搜索 | 邮箱 | 主页 | UC


加好友 发短信
等级:管理员 帖子:47497 积分:251403 威望:0 精华:91 注册:2008/6/17 17:14:00
高效随机抽取少量和大量记录的方法  发帖心情 Post By:2015/5/14 16:54:00 [只看该作者]

随机抽取少量记录

 

如果要从数据表中随机抽取一定数量的记录,例如从员工表随机抽取5个员工,可以参考下面的代码:

Dim ids As String
Dim
lst As new List(of String)
Dim
cnt As Integer = DataTables("员工").DataRows.Count
Do

    Dim Id As Integer = rand.Next(0,cnt)
    id = DataTables("员工").DataRows(id)("_Identify")
    If lst.Contains(id) =False Then
        lst.Add(id)
    End If
    ids = ids & id &
","

Loop
While lst.count < 5   '5是要抽取的行数
Tables
("员工").Filter = "[_Identify] In (" & ids.Trim(",") & ")"

 

上面的代码适合随机抽取少量的记录。

 

随机抽取大量记录

 

如果随机抽取的记录较多,可以考虑增加一个逻辑列,假定逻辑列的名称为“选择”,可以参考下面的代码:

 

Dim lst As new List(of Integer)
Dim
cnt As Integer = DataTables("订单").DataRows.Count
Tables
("订单").StopRedraw()
DataTables
("订单").ReplaceFor("选择",False)
Do

    Dim idx As Integer = rand.Next(0,cnt)
    If lst.Contains(idx) =False Then
        lst.Add(idx)
        DataTables(
"
订单").DataRows(idx)("选择") = True
    End
If

Loop
While lst.count < 100   '100是要抽取的行数
Tables
("订单").Filter = "[选择] = True"
Tables
("订单").ResumeRedraw()

 

上面的代码从订单表中随机抽取100个订单。
建议逻辑列“选择”采用表达式列,不要给其设置表达式即可,因为:没有设置表达式的表达式列,可以通过代码设置此列的值。


 回到顶部
帅哥哟,离线,有人找我吗?
Bin
  2楼 | 信息 | 搜索 | 邮箱 | 主页 | UC


加好友 发短信
等级:贵宾 帖子:35433 积分:178524 威望:0 精华:3 注册:2013/3/30 16:36:00
  发帖心情 Post By:2015/5/14 16:55:00 [只看该作者]

收藏.

 回到顶部
帅哥哟,离线,有人找我吗?
大红袍
  3楼 | 信息 | 搜索 | 邮箱 | 主页 | UC


加好友 发短信
等级:贵宾 帖子:39310 积分:196782 威望:0 精华:1 注册:2015/4/25 9:23:00
  发帖心情 Post By:2015/5/14 17:01:00 [只看该作者]

 还可以换一种思路,类似打扑克牌,洗牌切牌n次后,随便怎么取都可以。

 回到顶部
帅哥哟,离线,有人找我吗?
狐狸爸爸
  4楼 | 信息 | 搜索 | 邮箱 | 主页 | UC


加好友 发短信
等级:管理员 帖子:47497 积分:251403 威望:0 精华:91 注册:2008/6/17 17:14:00
  发帖心情 Post By:2015/5/14 17:10:00 [只看该作者]

嗯,一楼抽取大量记录的代码不太恰当,下面的代码应该高效很多,因为无需用集合来检索:

 

Dim cnt As Integer = DataTables("订单").DataRows.Count

Dim nds As Integer = 100 '要抽取的记录数

Tables("订单").StopRedraw()

DataTables("订单").ReplaceFor("选择",False)

Do

    Dim idx As Integer = rand.Next(0,cnt)

    Dim dr As DataRow = DataTables("订单").DataRows(idx)

    If dr("选择") = False Then

        dr("选择") = True

        nds = nds - 1

    End If

Loop While nds > 0

Tables("订单").Filter = "[选择] = True"

Tables("订单").ResumeRedraw()

[此贴子已经被作者于2015/5/14 17:13:55编辑过]

 回到顶部
帅哥哟,离线,有人找我吗?
狐狸爸爸
  5楼 | 信息 | 搜索 | 邮箱 | 主页 | UC


加好友 发短信
等级:管理员 帖子:47497 积分:251403 威望:0 精华:91 注册:2008/6/17 17:14:00
  发帖心情 Post By:2015/5/14 17:37:00 [只看该作者]

如果抽取数接近与总的记录数,那么3楼的代码也不太合适,虽然可以逆排除,但毕竟要多写代码。
所以还是洗牌的方法比较好,性能稳定:
 
Dim cnt As Integer = DataTables("订单").DataRows.Count
Dim ids(cnt - 1) As Integer
For i As Integer = 0 To cnt -1
    ids(i) = i
Next
For i As Integer = 0 To cnt \ 2 '洗牌
    Dim id1 As Integer = rand.Next(0,cnt)
    Dim id2 As Integer = rand.Next(0,cnt)
    Dim vid As Integer = ids(id1)
    ids(id1) = ids(id2)
    ids(id2) = vid
Next
Tables("订单").StopRedraw()
DataTables("订单").ReplaceFor("选择",False)
For i As Integer =  1 To 100 '100为要抽取的行数
    DataTables("订单").DataRows(ids(i-1))("选择") = True
Next
Tables("订单").Filter = "[选择] = True"
Tables("订单").ResumeRedraw()
[此贴子已经被作者于2015/5/14 17:37:58编辑过]

 回到顶部
帅哥哟,离线,有人找我吗?
yinyb36
  6楼 | 信息 | 搜索 | 邮箱 | 主页 | UC


加好友 发短信
等级:四尾狐 帖子:953 积分:7252 威望:0 精华:0 注册:2011/9/6 13:36:00
  发帖心情 Post By:2015/5/14 19:01:00 [只看该作者]

收藏

 回到顶部
帅哥哟,离线,有人找我吗?
黄训良
  7楼 | 信息 | 搜索 | 邮箱 | 主页 | UC


加好友 发短信
等级:五尾狐 帖子:1100 积分:8985 威望:0 精华:0 注册:2014/3/15 14:36:00
  发帖心情 Post By:2015/5/14 20:02:00 [只看该作者]

收藏。

 回到顶部
帅哥哟,离线,有人找我吗?
bohe
  8楼 | 信息 | 搜索 | 邮箱 | 主页 | UC


加好友 发短信
等级:五尾狐 帖子:1077 积分:9923 威望:0 精华:0 注册:2008/9/2 11:34:00
  发帖心情 Post By:2015/5/14 20:20:00 [只看该作者]

收藏

 回到顶部
帅哥哟,离线,有人找我吗?
有点酸
  9楼 | 信息 | 搜索 | 邮箱 | 主页 | UC


加好友 发短信
等级:五尾狐 帖子:1093 积分:6682 威望:0 精华:0 注册:2013/7/1 9:05:00
  发帖心情 Post By:2015/5/14 23:10:00 [只看该作者]

5楼洗牌的方法是错误的,会导致靠前的记录被抽取的概率大,下面这样,前后的机会才均等:

 

Dim cnt As Integer = DataTables("订单").DataRows.Count
Dim ids(cnt - 1) As Integer
Dim rnd(cnt -1) As Integer
For i As Integer = 0 To cnt -1
    ids(i) = i
    rnd(i) = rand.Next(0,cnt)
Next
array.sort(rnd,ids)
Tables("订单").StopRedraw()
DataTables("订单").ReplaceFor("选择",False)
For i As Integer =  1 To 100 '100为要抽取的行数
    DataTables("订单").DataRows(ids(i-1))("选择") = True
Next
Tables("订单").Filter = "[选择] = True"
Tables("订单").ResumeRedraw()

 

但是Array.Sort帮助没有介绍,下面的代码完全采用帮助的知识,性能基本一致:

 

Dim cnt As Integer = DataTables("订单").DataRows.Count
Dim ids As New List(of Integer)
For i As Integer = 0 To cnt -1
    ids.add(i)
Next
Do
    Dim n As Integer = rand.Next(0,ids.count)
    ids.RemoveAt(n)
Loop While ids.count > 100  '100为要随机抽取的行数
Tables("订单").StopRedraw()
DataTables("订单").ReplaceFor("选择",False)
For Each i As Integer In ids
    DataTables("订单").DataRows(i)("选择") = True
Next
Tables("订单").Filter = "[选择] = True"
Tables("订单").ResumeRedraw()

 

[此贴子已经被作者于2015/5/14 23:14:15编辑过]

 回到顶部
帅哥哟,离线,有人找我吗?
blackzhu
  10楼 | QQ | 信息 | 搜索 | 邮箱 | 主页 | UC


加好友 发短信 一级勋章
等级:狐仙 帖子:9879 积分:57634 威望:0 精华:15 注册:2008/9/1 9:45:00
  发帖心情 Post By:2015/5/15 7:54:00 [只看该作者]

牛B ! 收藏着

 回到顶部
总数 24 1 2 3 下一页