以文本方式查看主题

-  Foxtable(狐表)  (http://foxtable.com/bbs/index.asp)
--  专家坐堂  (http://foxtable.com/bbs/list.asp?boardid=2)
----  高效随机抽取少量和大量记录的方法  (http://foxtable.com/bbs/dispbbs.asp?boardid=2&id=68314)

--  作者:狐狸爸爸
--  发布时间: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
--  发布时间:2015/5/14 16:55:00
--  
收藏.
--  作者:大红袍
--  发布时间:2015/5/14 17:01:00
--  
 还可以换一种思路,类似打扑克牌,洗牌切牌n次后,随便怎么取都可以。
--  作者:狐狸爸爸
--  发布时间: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编辑过]

--  作者:狐狸爸爸
--  发布时间: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
--  发布时间:2015/5/14 19:01:00
--  
收藏
--  作者:黄训良
--  发布时间:2015/5/14 20:02:00
--  
收藏。
--  作者:bohe
--  发布时间:2015/5/14 20:20:00
--  
收藏
--  作者:有点酸
--  发布时间: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
--  发布时间:2015/5/15 7:54:00
--  
牛B ! 收藏着