2009-02-16 9 views
6

Ich habe eine Liste des Typs System.IO.FileInfo, und ich möchte die Liste randomisieren. Ich dachte, ich erinnere mich, dass ich vor einiger Zeit etwas wie list.randomize() gesehen habe, aber ich kann nicht herausfinden, wo ich das gesehen haben könnte.Gibt es eine einfache Möglichkeit, eine Liste in VB.NET zu randomisieren?

Mein erster Ausflug in diese ergab mich mit dieser Funktion.

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 

ich es senden die max val ich möchte es, wiederholen und ein Verweis auf die Liste möchte ich den randomisierten Inhalt in der Die Variable IMG_COUNT ist weiter oben im Skript festgelegt und gibt an, wie viele zufällige Bilder angezeigt werden sollen.

Danke Jungs, ich schätze es: D

Antwort

2

einen Comparer Körperbau:

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 

es so verwenden Sie eine generische List(Of FileInfo) bedeuten unter der Annahme: auch

list.Sort(New Randomizer(Of IO.FileInfo)()) 

Sie einen Verschluss verwenden, um den Zufallswert ‚klebrig‘ zu machen und dann nur Linq der .OrderBy() auf diesem verwenden (C# dieses Mal, weil die VB Lambda-Syntax ist hässlich):

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

erklärt hier, zusammen mit, warum es nicht einmal so schnell wie echte Shuffle sein könnte:
http://www.codinghorror.com/blog/archives/001008.html?r=31644

+0

Ich bekomme immer einen Fehler: "Class 'Randomizer' muss 'Funktion Compare (x als T, y als T) As Integer' für die Schnittstelle 'System.Collections.Generic.IComparer (of T)' implementieren." Dieser Fehler wird nur mit Ihrem zweiten Codeblock erhalten. – Anders

+0

Beachten Sie, dass diese Methode bei der zweiten Option nicht in einer separaten Klasse leben muss, und Sie verwenden sie wie gezeigt mithilfe des AddressOf-Operators, anstatt eine Klasseninstanz zu erstellen. –

+1

-1: Nur eine schlechte Implementierung. Die Funktion sticht eigentlich nichts zufällig auf, weil zwei Listen, die die gleichen Elemente enthalten, in der gleichen Reihenfolge "randomisiert" werden. Nichts hindert sequentielle Objekte daran, sequentielle Hashcodes zu haben. Es gibt viel bessere Möglichkeiten, diese Funktion zu schreiben. – Juliet

-2

Sie benutzerdefinierte Vergleich erstellen könnte, die nur eine Zufallszahl zurückgibt, die Liste sortieren diese Vergleichs. Es könnte schrecklich ineffizient sein und eine fast endlose Schleife verursachen, aber es könnte einen Versuch wert sein.

+0

in anderen Worte, ist meine Methode ein guter Weg zu gehen? – Anders

+0

Nein, Sie möchten auf jeden Fall Array.Sort() mit einigen benutzerdefinierten Komparator verwenden. Es ist nur eine Frage der Implementierung des Komparators -> möglicherweise basierend auf dem Wert GetHashCode() jedes Objekts. –

+0

Gibt es irgendwelche guten Ressourcen, die Sie für benutzerdefinierte Komparatoren kennen? Ich habe in letzter Zeit nicht viel in die Leute hineingeschaut. * Enten * – Anders

1

Sie können auch eine Shuffle, viele Möglichkeiten, dies zu tun, die einfachste ist zufällig ein Element auswählen und fügen Sie es an einem neuen Ort ein paar Mal.

0

Wenn Sie die Anzahl der Elemente haben, kann eine Pseudozufallsmethode verwendet werden, wobei Sie das erste Element nach dem Zufallsprinzip auswählen (z. B. mit der eingebauten Zufallszahlenfunktion), dann eine Primzahl hinzufügen und nach der Division den Rest nehmen von Werten. z.B. Für eine Liste von 10 könnten Sie i = (i + prime)% 10 verwenden, um Indizes von einem Anfangswert zu erzeugen. Solange die Primzahl größer als die Anzahl der Werte in der Liste ist, erstellen Sie eine Sequenz, die alle Zahlen 0 ... n durchläuft, wobei n die Anzahl der Werte - 1 ist, aber in einer Pseudozufallsreihenfolge.

2

Es gibt mehrere vernünftige Methoden der schlurfenden.

Einer wurde bereits erwähnt. (Der Knuth Shuffle.)

Eine andere Methode wäre, jedem Element ein "Gewicht" zuzuweisen und die Liste nach diesem "Gewicht" zu sortieren. Diese Methode ist möglich, würde aber nicht sinnvoll sein, da Sie nicht von FileInfo erben können.

Eine letzte Methode wäre, ein Element in der ursprünglichen Liste nach dem Zufallsprinzip auszuwählen und es zu einer neuen Liste hinzuzufügen. Natürlich, wenn es Ihnen nichts ausmacht, eine neue Liste zu erstellen. (Haben Sie diesen Code nicht getestet ...)


     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 
+0

cool, krank behalte das für die zukunft im kopf. – Anders

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 
+0

Wenn Sie einfach "oRand.Next (0, currentVals.Count)" durch "oRand.Next (x, currentVals.Count)" ersetzen, erhalten Sie eine bessere zufällige Verteilung. Siehe [Jeff Atwoods aufschlussreicher Blogpost] (http://www.codinghorror.com/blog/2007/12/the-danger-of-naivete.html). –

5

Ich habe verlängert die List Klasse mit der folgenden Randomize() Funktion des Fisher-Yates Shuffle-Algorithmus zu verwenden:

''' <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 
Verwandte Themen