2010-01-07 19 views

Respuesta

289
  1. Crea una instancia de Random clase en alguna parte. Tenga en cuenta que es muy importante no crear una nueva instancia cada vez que necesite un número aleatorio. Debe reutilizar la instancia anterior para lograr la uniformidad en los números generados. Puede tener un campo static en alguna parte (tener cuidado con las cuestiones de seguridad de rosca):

    static Random rnd = new Random(); 
    
  2. Pregunte la instancia Random para darle un número aleatorio con el máximo de la cantidad de elementos en el ArrayList:

    int r = rnd.Next(list.Count); 
    
  3. mostrar la cadena:

    MessageBox.Show((string)list[r]); 
    
+0

¿Hay alguna buena manera para modificar esto para que un número no se repita? Digamos que quería barajar una baraja de cartas seleccionando una a la vez, pero obviamente no puedo seleccionar la misma carta dos veces. – AdamMc331

+5

@ McAdam331 Busque el algoritmo de búsqueda aleatoria de Fisher-Yates: http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle –

+2

¿Debería ser "rnd.Next (list.Count-1)" en lugar de "rnd"? .Next (list.Count) "para evitar el acceso al elemento max, que sería uno más allá del índice presumiblemente 0-based? –

15

Crear una instancia Random:

Random rnd = new Random(); 

buscar una cadena aleatoria:

string s = arraylist[rnd.Next(arraylist.Count)]; 

recordar, sin embargo, que si usted hace esto con frecuencia debe volver a utilizar el objeto Random. Póngalo como un campo estático en la clase, de modo que se inicialice solo una vez y luego acceda a él.

103

normalmente utilizo esta pequeña colección de métodos de extensión:

public static class EnumerableExtension 
{ 
    public static T PickRandom<T>(this IEnumerable<T> source) 
    { 
     return source.PickRandom(1).Single(); 
    } 

    public static IEnumerable<T> PickRandom<T>(this IEnumerable<T> source, int count) 
    { 
     return source.Shuffle().Take(count); 
    } 

    public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> source) 
    { 
     return source.OrderBy(x => Guid.NewGuid()); 
    } 
} 

Para obtener una lista estricta de tipos, esto permitiría a escribir:

var strings = new List<string>(); 
var randomString = strings.PickRandom(); 

Si todo lo que tiene es un ArrayList, puede convertir que:

var strings = myArrayList.Cast<string>(); 
+0

¿cuál es la complejidad de esos? ¿la naturaleza perezosa de IEnumerable significa que no es O (N)? –

+8

Esta respuesta vuelve a mezclar la lista cada vez que selecciona un número aleatorio. Sería mucho más eficiente devolver un valor de índice aleatorio, especialmente para listas grandes. Use esto en PickRandom - 'lista de devolución [rnd.Next (list.Count)];' – swax

+0

Esto no mezcla la lista original, de hecho en otra lista que aún no es buena para la eficiencia si la lista es lo suficientemente grande .. – nawfal

70

que puede hacer:

list.OrderBy(x => Guid.NewGuid()).FirstOrDefault() 
+0

Hermoso. EN ASP.NET MVC 4.5, uisng a list, tuve que cambiar esto a: list.OrderBy (x => Guid.NewGuid()). FirstOrDefault(); –

+2

No importará en la mayoría de los casos pero esto es probablemente mucho más lento que usar rnd.Next. OTOH funcionará en IEnumerable , no solo listas. – solublefish

+8

No estoy seguro de qué tan aleatorio es eso. Los guids son únicos, no aleatorios. – pomber

2
ArrayList ar = new ArrayList(); 
     ar.Add(1); 
     ar.Add(5); 
     ar.Add(25); 
     ar.Add(37); 
     ar.Add(6); 
     ar.Add(11); 
     ar.Add(35); 
     Random r = new Random(); 
     int index = r.Next(0,ar.Count-1); 
     MessageBox.Show(ar[index].ToString()); 
+3

Si bien este fragmento de código puede resolver la pregunta, [incluyendo una explicación] (http://meta.stackexchange.com/questions/114762/explaining-entirely-code-based-answers) realmente ayuda a mejorar la calidad de su publicación. Recuerde que usted está respondiendo la pregunta a los lectores en el futuro, y es posible que esas personas no sepan los motivos de su sugerencia de código. – gunr2171

+2

Diría que el parámetro 'maxValue' del método' Next' debe ser solo un número de elementos en una lista, no menos uno, porque según una documentación "* maxValue es el ** límite superior exclusivo ** del número aleatorio*". –

9

O clase simple extensión de la siguiente manera:

public static class CollectionExtension 
{ 
    private static Random rng = new Random(); 

    public static T RandomElement<T>(this IList<T> list) 
    { 
     return list[rng.Next(list.Count)]; 
    } 

    public static T RandomElement<T>(this T[] array) 
    { 
     return array[rng.Next(array.Length)]; 
    } 
} 

A continuación, sólo llaman:

myList.RandomElement(); 

a los arrays así.

Evitaría llamar a OrderBy() ya que puede ser costoso para colecciones más grandes. Use colecciones indexadas como List<T> o matrices para este fin.

+1

Las matrices en .NET ya implementan 'IList', por lo que la segunda sobrecarga es innecesaria. – Dai

0

He estado usando este ExtensionMethod por un tiempo:

public static IEnumerable<T> GetRandom<T>(this IEnumerable<T> list, int count) 
{ 
    if (count <= 0) 
     yield break; 
    var r = new Random(); 
    int limit = (count * 10); 
    foreach (var item in list.OrderBy(x => r.Next(0, limit)).Take(count)) 
     yield return item; 
} 
+0

Olvidaste agregar una instancia de clase aleatoria – bafsar

0

que necesitaba más artículo en lugar de sólo uno. Por lo tanto, escribí esto:

public static TList GetSelectedRandom<TList>(this TList list, int count) 
     where TList : IList, new() 
{ 
    var r = new Random(); 
    var rList = new TList(); 
    while (count > 0 && list.Count > 0) 
    { 
     var n = r.Next(0, list.Count); 
     var e = list[n]; 
     rList.Add(e); 
     list.RemoveAt(n); 
     count--; 
    } 

    return rList; 
} 

Con esto, usted puede obtener elementos de la cantidad que desea como al azar como esto:

var _allItems = new List<TModel>() 
{ 
    // ... 
    // ... 
    // ... 
} 

var randomItemList = _allItems.GetSelectedRandom(10); 
2
Por qué no

:

public static T GetRandom<T>(this IEnumerable<T> list) 
{ 
    return list.ElementAt(new Random(DateTime.Now.Millisecond).Next(list.Count())); 
} 
Cuestiones relacionadas