2009-02-16 24 views
6

Tengo una lista del tipo System.IO.FileInfo, y me gustaría aleatorizar la lista. Pensé que recuerdo haber visto algo así como list.randomize() hace un tiempo, pero no puedo encontrar dónde pude haber visto eso.¿Existe alguna manera fácil de aleatorizar una lista en VB.NET?

Mi primera incursión en esto me dio con esta función:.

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 

lo envío al máximo val quiero que iterar hasta, y una referencia a la lista Quiero el contenido aleatorio en el La variable IMG_COUNT se coloca más arriba en la secuencia de comandos y designa cuántas imágenes aleatorias quiero mostrar.

Gracias chicos, lo agradezco: D

Respuesta

2

Construir un comparador:

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 

utilizar de esta manera, suponiendo que se refiere a un genérico List(Of FileInfo):

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

También puede utilizar un cierre para hacer que el valor aleatorio 'pegajoso' y luego solo use linq's .OrderBy() en eso (C# esta vez, porque la sintaxis VB lambda es fea):

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

explicados aquí, junto con la razón por la que podría incluso no ser tan rápido como aleatoria real:
http://www.codinghorror.com/blog/archives/001008.html?r=31644

+0

Recibo un error: "Class 'Randomizer' debe implementar 'Function Compare (x como T, y como T) As Integer' para la interfaz 'System.Collections.Generic.IComparer (of T)'." Este error se obtiene simplemente usando su segundo bloque de código. – Anders

+0

Tenga en cuenta que con la segunda opción, ese método no necesita vivir en una clase separada, y lo usa a través del operador AddressOf como se muestra, en lugar de crear una instancia de clase. –

+1

-1: solo una mala implementación. La función en realidad no aleatoriza nada, porque dos listas que contienen los mismos elementos serán "aleatorizadas" en el mismo orden. Además, nada impide que los elementos secuenciales tengan códigos hash secuenciales. Hay formas mucho mejores de escribir esta función. – Juliet

-2

Se puede crear comparador personalizado que sólo devuelve un número al azar, a continuación, ordenar la lista con este comparador. Podría ser terriblemente ineficiente y causar un ciclo casi infinito, pero podría valer la pena intentarlo.

+0

en otra palabras, ¿es mi método una buena forma de hacerlo? – Anders

+0

No, definitivamente quiere usar array.Sort() con algún comparador personalizado. Es solo una cuestión de cómo implementar el comparador-> posiblemente basado en el valor GetHashCode() de cada objeto. –

+0

¿hay algún recurso que conozca para los comparadores personalizados? No he visto mucho en los últimos * patos * – Anders

1

También podría implementar una mezcla aleatoria, de muchas maneras para hacer esto, la más simple es elegir aleatoriamente un elemento e insertarlo en una nueva ubicación un montón de veces.

0

Si tiene la cantidad de elementos, se puede usar un método pseudoaleatorio donde elige el primer elemento al azar (por ejemplo, usando la función de número aleatorio incorporado) y luego agregar un primo y tomar el resto después de la división por el número de valores p.ej. para una lista de 10, podría hacer i = (i + prime)% 10 para los índices generados i a partir de algún valor inicial. Siempre que el primo sea mayor que el número de valores en la lista, entonces usted crea una secuencia que se ejecuta a través de todos los números 0 ... n donde n es el número de valores - 1, pero en un orden pseudoaleatorio.

2

Hay varios métodos razonables de barajar.

Uno ya ha sido mencionado. (The Knuth Shuffle.)

Otro método sería asignar un "peso" a cada elemento y ordenar la lista según ese "peso". Este método es posible pero sería poco sofisticado porque no puede heredar de FileInfo.

Un método final sería seleccionar aleatoriamente un elemento en la lista original y agregarlo a una nueva lista. Por supuesto, eso es, si no te importa crear una nueva lista. (No hemos probado este código ...)


     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

genial, lo tendré en cuenta para el futuro. – 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

Si simplemente reemplaza 'oRand.Next (0, currentVals.Count)' con 'oRand.Next (x, currentVals.Count)', obtendrá una mejor distribución aleatoria. Ver [la perspicaz publicación de blog de Jeff Atwood] (http://www.codinghorror.com/blog/2007/12/the-danger-of-naivete.html). –

5

he ampliado la clase List con la siguiente función Randomize() utilizar el Algoritmo Fisher-Yates algoritmo:

''' <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 
Cuestiones relacionadas