Есть ли простой способ рандомизировать список в VB.NET? - PullRequest
6 голосов
/ 17 февраля 2009

У меня есть список типа 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

Ответы [ 8 ]

14 голосов
/ 17 февраля 2009

Проверьте алгоритм тасования Фишера-Йейтса здесь: http://en.wikipedia.org/wiki/Knuth_shuffle

с более кратким обсуждением главного повелителя этого сайта здесь: http://www.codinghorror.com/blog/archives/001015.html

В записи блога есть простая реализация на C #, которую очень легко заменить на VB.NET

5 голосов
/ 22 сентября 2011

Я расширил класс List с помощью следующей функции Randomize(), чтобы использовать алгоритм перемешивания Фишера-Йейтса:

''' <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 голосов
/ 17 февраля 2009

Существует несколько разумных способов перетасовки.

Один уже был упомянут. (Кнут Шаффл.)

Другим способом было бы назначить «вес» каждому элементу и отсортировать список по этому «весу». Этот метод возможен, но будет неудобен, потому что вы не можете наследовать от 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
2 голосов
/ 17 февраля 2009

Создание компаратора:

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)())

Вы также можете использовать замыкание, чтобы сделать случайное значение «липким», а затем просто использовать linq .OrderBy () для этого (на этот раз C #, потому что лямбда-синтаксис VB безобразен):

list = list.OrderBy(a => Guid.NewGuid()).ToList();

Объясняется здесь, а также почему он может быть не таким быстрым, как настоящий случайный случай:
http://www.codinghorror.com/blog/archives/001008.html?r=31644

1 голос
/ 17 февраля 2009

Вы также можете реализовать случайное перемешивание, множество способов сделать это, самый простой - случайным образом выбрать предмет и вставить его в новое место несколько раз.

0 голосов
/ 20 февраля 2009
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
0 голосов
/ 17 февраля 2009

Если у вас есть количество элементов, то можно использовать псевдослучайный метод, при котором вы выбираете первый элемент случайным образом (например, с помощью встроенной функции случайных чисел), затем добавляете простое число и берете остаток после деления на число ценности. например для списка из 10 вы можете сделать i = (i + prime)% 10, чтобы сгенерировать индексы i из некоторого начального значения. Пока простое число больше числа значений в списке, вы создаете последовательность, которая проходит через все числа 0 ... n, где n - это число значений - 1, но в псевдослучайном порядке.

0 голосов
/ 17 февраля 2009

Вы можете создать собственный компаратор, который просто возвращает случайное число, а затем отсортировать список с помощью этого компаратора. Это может быть ужасно неэффективно и привести к почти бесконечному циклу, но, возможно, стоит попробовать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...