Vb.net 随机化列表
我有这个代码,它工作得很好。输入列表被很好地随机洗牌 但我在理解它为什么起作用方面有点困难 具体来说,Vb.net 随机化列表,vb.net,list,random,shuffle,Vb.net,List,Random,Shuffle,我有这个代码,它工作得很好。输入列表被很好地随机洗牌 但我在理解它为什么起作用方面有点困难 具体来说,oBuffer在这一切中扮演什么角色?为什么要在最后一行: oBuffer(iRandom) = oBuffer(iIndex) 我发现当我对它进行注释时,输出列表中会出现重复项 我已经通过了密码,但我仍然不知所措。这到底是怎么回事 <Extension> Public Iterator Function Randomize(Of T)(Instance As IEnume
oBuffer
在这一切中扮演什么角色?为什么要在最后一行:
oBuffer(iRandom) = oBuffer(iIndex)
我发现当我对它进行注释时,输出列表中会出现重复项
我已经通过了密码,但我仍然不知所措。这到底是怎么回事
<Extension>
Public Iterator Function Randomize(Of T)(Instance As IEnumerable(Of T), Rng As Random) As IEnumerable(Of T)
Dim oBuffer As List(Of T)
Dim iRandom As Integer
Dim iIndex As Integer
Instance.ThrowIfNothing(NameOf(Instance))
Rng.ThrowIfNothing(NameOf(Rng))
oBuffer = Instance.ToList
For iIndex = 0 To oBuffer.Count - 1
iRandom = Rng.Next(iIndex, oBuffer.Count)
Yield oBuffer(iRandom)
oBuffer(iRandom) = oBuffer(iIndex)
Next
End Function
公共迭代器函数随机化(Of T)(实例为IEnumerable(Of T),Rng为Random)为IEnumerable(Of T)
Dim OBUFER As列表(共T个)
Dim iRandom作为整数
作为整数的Dim iIndex
Instance.ThrowIfNothing(name of(Instance))
Rng.ThrowIfNothing(名称(Rng))
oBuffer=Instance.ToList
对于iIndex=0的对象,计数为-1
iRandom=Rng.Next(iIndex,oBuffer.Count)
产量OBUFER(伊兰多姆)
oBuffer(iRandom)=oBuffer(iIndex)
下一个
端函数
备选方案(AltRandomize)。请注意,此方法不需要向其传递随机实例
Imports System.Runtime.CompilerServices
Module ModExtensions
Public PRNG As New Random
<Extension>
Public Iterator Function AltRandomize(Of T)(Instance As IEnumerable(Of T)) As IEnumerable(Of T)
Dim oBuffer As List(Of T)
'uncomment following
'Instance.ThrowIfNothing(NameOf(Instance))
oBuffer = Instance.OrderBy(Function(n) PRNG.Next()).ToList
For iIndex As Integer = 0 To oBuffer.Count - 1
Yield oBuffer(iIndex)
Next
oBuffer.Clear()
End Function
<Extension>
Public Iterator Function Randomize(Of T)(Instance As IEnumerable(Of T), Rng As Random) As IEnumerable(Of T)
Dim oBuffer As List(Of T)
Dim iRandom As Integer
Dim iIndex As Integer
'Instance.ThrowIfNothing(NameOf(Instance))
'Rng.ThrowIfNothing(NameOf(Rng))
oBuffer = Instance.ToList
For iIndex = 0 To oBuffer.Count - 1
iRandom = Rng.Next(iIndex, oBuffer.Count)
Yield oBuffer(iRandom)
oBuffer(iRandom) = oBuffer(iIndex)
Next
End Function
End Module
导入System.Runtime.CompilerServices
模块ModExtensions
公营公共房屋小组委员会
公共迭代器函数AltRandomize(Of T)(实例为IEnumerable(Of T))为IEnumerable(Of T)
Dim OBUFER As列表(共T个)
'取消以下注释
'Instance.ThrowIfNothing(name of(Instance))
oBuffer=Instance.OrderBy(函数(n)PRNG.Next()).ToList
对于iIndex作为整数=0到oBuffer.Count-1
产量指标(iIndex)
下一个
oBuffer.Clear()
端函数
公共迭代器函数随机化(Of T)(实例为IEnumerable(Of T),Rng为Random)为IEnumerable(Of T)
Dim OBUFER As列表(共T个)
Dim iRandom作为整数
作为整数的Dim iIndex
'Instance.ThrowIfNothing(name of(Instance))
“Rng.ThrowIfNothing(名称(Rng))
oBuffer=Instance.ToList
对于iIndex=0的对象,计数为-1
iRandom=Rng.Next(iIndex,oBuffer.Count)
产量OBUFER(伊兰多姆)
oBuffer(iRandom)=oBuffer(iIndex)
下一个
端函数
端模块
oBuffer
包含原始列表的副本,无论该列表包含什么
该函数在列表中迭代,如下所示:
的每个循环中,都会生成一个随机数,它基本上是一个优于当前项的索引号
生成
随机项(将其作为当前正在构建的新列表的下一个元素返回,从索引0开始)现在你必须通过注释掉最后一行来理解为什么你得到了双倍:它在那里是为了确保当前项目也将被随机分配。这有点像在你面前铲东西,以确保你不会忘记一个,也不会在
Yield
ed时再次使用一个。这是Fisher-Yates shuffle的一个实现。有一个描述算法的例子。我相信(基于对文章的回顾)为了实现具有线性时间复杂度的算法,就地缓冲区是必要的;如果使用单独的暂存缓冲区,则算法将是O(n²)而不是O(n)。oBuffer是原始缓冲区的副本。可能是用来保护原始列表的。我添加了一个具有可选FWIW的答案。@dbasnett该函数将IEnumerable
而不是列表作为参数oBuffer
具体化并捕获可枚举的初始内容(可能已延迟)。这是一个很好的解释。请注意,当取消注释循环的最后一行时,oBuffer(iRandom)=oBuffer(iIndex)
,oBuffer
在循环退出时包含重复项。我决定接受。他引用的维基百科文章非常详细地解释了这一点。YW,我感谢你的考虑。我喜欢这个替代品。事实上,我们似乎可以完全不用迭代器/Yield
构造<代码>返回Instance.OrderBy(函数(n)PRNG.Next())
FYI这是一对重载扩展方法中的第二个。第一个使用一个新的Random
对象调用这个。这一点的存在是为了解决相同序列的问题,如图1所示。“…由于前两个随机对象是紧密连续创建的,因此根据系统时钟使用相同的种子值对它们进行实例化,因此,它们产生相同的随机数序列。”@InteXX-替代方案将只有一个随机实例。如果需要访问应用程序中其他地方的随机对象,只需使用模块中指定的对象。@InteXX迭代器/Yield的使用部分取决于预期用途。如果您总是想要完整的列表(例如,一个纸牌游戏,您总是要处理整个牌组),那么您不需要迭代器。另一方面,如果您通常只需要列表中的一部分,迭代器版本会更有效,因为它只会生成您请求的项目(例如,像扑克这样的纸牌游戏,其中只处理/使用了一部分纸牌)。另一种选择将只有一个随机的实例。
好的,我现在发现了。