我有一个System.IO.FileInfo
类型的列表,我想随机列表。我以为我记得有一段时间看到像list.randomize()
这样的东西,但我找不到我可能已经看到过的地方。
我对此的第一次尝试使我获得了这个功能:
Private Shared Sub GetRandom(ByVal oMax As Integer, ByRef currentVals As List(Of Integer))
Dim oRand As New Random(Now.Millisecond)
Dim oTemp As Integer = -1
Do Until currentVals.Count = IMG_COUNT
oTemp = oRand.Next(1, oMax)
If Not currentVals.Contains(oTemp) Then currentVals.Add(oTemp)
Loop
End Sub
我发送它想要它迭代的最大值,以及对列表的引用我想要随机化的内容。变量IMG_COUNT
在脚本中设置得更远,指定了多少随机图像我想要显示。
谢谢大家,我很感激:D
答案 0 :(得分:14)
在这里查看Fisher-Yates shuffle算法:http://en.wikipedia.org/wiki/Knuth_shuffle
这个网站的主要负责人在这里进行了更为简洁的讨论: http://www.codinghorror.com/blog/archives/001015.html
博客条目中有一个简单的C#实现,应该很容易更改为VB.NET
答案 1 :(得分:5)
我使用以下List
函数扩展了Randomize()
类,以使用Fisher-Yates shuffle算法:
''' <summary>
''' Randomizes the contents of the list using Fisher–Yates shuffle (a.k.a. Knuth shuffle).
''' </summary>
''' <typeparam name="T"></typeparam>
''' <param name="list"></param>
''' <returns>Randomized result</returns>
''' <remarks></remarks>
<Extension()>
Function Randomize(Of T)(ByVal list As List(Of T)) As List(Of T)
Dim rand As New Random()
Dim temp As T
Dim indexRand As Integer
Dim indexLast As Integer = list.Count - 1
For index As Integer = 0 To indexLast
indexRand = rand.Next(index, indexLast)
temp = list(indexRand)
list(indexRand) = list(index)
list(index) = temp
Next index
Return list
End Function
答案 2 :(得分:2)
建立一个比较者:
Public Class Randomizer(Of T)
Implements IComparer(Of T)
''// Ensures different instances are sorted in different orders
Private Shared Salter As New Random() ''// only as random as your seed
Private Salt As Integer
Public Sub New()
Salt = Salter.Next(Integer.MinValue, Integer.MaxValue)
End Sub
Private Shared sha As New SHA1CryptoServiceProvider()
Private Function HashNSalt(ByVal x As Integer) As Integer
Dim b() As Byte = sha.ComputeHash(BitConverter.GetBytes(x))
Dim r As Integer = 0
For i As Integer = 0 To b.Length - 1 Step 4
r = r Xor BitConverter.ToInt32(b, i)
Next
Return r Xor Salt
End Function
Public Function Compare(x As T, y As T) As Integer _
Implements IComparer(Of T).Compare
Return HashNSalt(x.GetHashCode()).CompareTo(HashNSalt(y.GetHashCode()))
End Function
End Class
使用它,假设您的意思是通用List(Of FileInfo)
:
list.Sort(New Randomizer(Of IO.FileInfo)())
你也可以使用一个闭包来使随机值'sticky',然后只使用linq的.OrderBy()(这次是C#,因为VB lambda语法很难看):
list = list.OrderBy(a => Guid.NewGuid()).ToList();
这里解释一下,为什么它甚至可能不如真正的洗牌一样快:
http://www.codinghorror.com/blog/archives/001008.html?r=31644
答案 3 :(得分:2)
有几种合理的改组方法。
已经提到了一个。 (The Knuth Shuffle。)
另一种方法是为每个元素分配一个“权重”,并根据“权重”对列表进行排序。这种方法是可行的,但是因为你不能从FileInfo继承而无法解决这个问题。
最后一种方法是随机选择原始列表中的元素并将其添加到新列表中。当然,也就是说,如果你不介意创建一个新列表。 (尚未测试此代码......)
Dim rnd As New Random
Dim lstOriginal As New List(Of FileInfo)
Dim lstNew As New List(Of FileInfo)
While lstOriginal.Count > 0
Dim idx As Integer = rnd.Next(0, lstOriginal.Count - 1)
lstNew.Add(lstOriginal(idx))
lstOriginal.RemoveAt(idx)
End While
答案 4 :(得分:1)
你也可以实现一个shuffle,有很多方法可以做到这一点,最简单的方法是随机选择一个项目并将其多次插入一个新的位置。
答案 5 :(得分:0)
如果你有元素的数量,那么可以使用伪随机方法,你随机选择第一个元素(例如使用内置的随机数函数),然后添加一个素数,并将除数后的余数除以值。例如对于10的列表,你可以做i =(i + prime)%10从一些起始值生成索引i。只要素数大于列表中的值的数量,那么您创建一个序列,该序列遍历所有数字0 ... n,其中n是值的数量-1,但是以伪随机顺序。
答案 6 :(得分:0)
Dim oRand As New Random() 'do not seed!!!!
Private Sub GetRandom(ByRef currentVals As List(Of Integer))
Dim i As New List(Of Integer), j As Integer
For x As Integer = 0 To currentVals.Count - 1
j = oRand.Next(0, currentVals.Count)
i.Add(currentVals(j))
currentVals.RemoveAt(j)
Next
currentVals = i
End Sub
答案 7 :(得分:-2)
您可以创建只返回随机数的自定义比较器,然后使用此比较器对列表进行排序。它可能非常低效并导致几乎无限循环,但可能值得一试。