2010-01-07 5 views

Répondre

289
  1. Créez une instance de classe Random quelque part. Notez qu'il est important de ne pas créer une nouvelle instance chaque fois que vous avez besoin d'un nombre aléatoire. Vous devez réutiliser l'ancienne instance pour obtenir l'uniformité des nombres générés. Vous pouvez avoir un champ static quelque part (attention sur les questions de sécurité de fil):

    static Random rnd = new Random(); 
    
  2. Demandez l'instance Random pour vous donner un nombre aléatoire au maximum le nombre d'éléments dans le ArrayList:

    int r = rnd.Next(list.Count); 
    
  3. Afficher la chaîne:

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

est-il un bon moyen modifier cela afin qu'un nombre ne soit pas répété? Disons que je voulais mélanger un jeu de cartes en en sélectionnant aléatoirement un à la fois, mais je ne peux évidemment pas sélectionner deux fois la même carte. – AdamMc331

+5

@ McAdam331 Recherchez l'algorithme de Fisher-Yates Shuffle: http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle –

+2

Devrait-il s'agir de "rnd.Next (list.Count-1)" au lieu de "rnd .Next (list.Count) "pour éviter d'accéder à l'élément max, qui serait un au-delà de l'index probablement basé sur 0? –

15

Créer une Random exemple:

Random rnd = new Random(); 

Fetch une chaîne aléatoire:

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

Rappelez-vous cependant, que si vous faites cela, vous devez souvent réutiliser l'objet Random. Placez-le comme un champ statique dans la classe afin qu'il ne soit initialisé qu'une seule fois et y accède ensuite.

103

Je l'habitude d'utiliser cette petite collection de méthodes d'extension:

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

Pour une liste fortement typé, cela vous permet d'écrire:

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

Si tout ce que vous avez est un ArrayList, vous pouvez lancer il:

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

quelle est la complexité de ceux-ci? la nature paresseuse de IEnumerable signifie-t-elle que ce n'est pas O (N)? –

+8

Cette réponse réorganise la liste chaque fois que vous choisissez un nombre aléatoire. Il serait beaucoup plus efficace de renvoyer une valeur d'index aléatoire, en particulier pour les grandes listes. Utilisez ceci dans PickRandom - 'return list [rnd.Next (list.Count)];' – swax

+0

Cela ne mélange pas la liste d'origine, il le fait sur une autre liste en fait, ce qui peut ne pas être bon pour l'efficacité si la liste est assez grande .. – nawfal

70

Vous pouvez faire:

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

Magnifique. Dans ASP.NET MVC 4.5, en utilisant une liste, j'ai dû changer cela pour: list.OrderBy (x => Guid.NewGuid()). FirstOrDefault(); –

+2

Cela ne sera pas important dans la plupart des cas, mais c'est probablement beaucoup plus lent que d'utiliser rnd.Next. OTOH cela fonctionnera sur IEnumerable , pas seulement des listes. – solublefish

+8

Je ne sais pas comment c'est aléatoire. Les guids sont uniques, pas aléatoires. – 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

Bien que cet extrait de code puisse résoudre la question, [y compris une explication] (http://meta.stackexchange.com/questions/114762/explaining-entirely-code-based-answers) aide vraiment à améliorer la qualité de votre message. Rappelez-vous que vous répondez à la question pour les lecteurs dans le futur, et que ces personnes pourraient ne pas connaître les raisons de votre suggestion de code. – gunr2171

+2

Je dirais que le paramètre 'maxValue' de la méthode' Next' devrait être juste un nombre d'éléments dans une liste, pas moins un, car selon une documentation "* maxValue est la ** limite supérieure exclusive ** du nombre aléatoire*". –

9

simple ou classe d'extension comme ceci:

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)]; 
    } 
} 

Ensuite il suffit d'appeler:

myList.RandomElement(); 

Works pour les tableaux ainsi.

J'éviter d'appeler OrderBy() car il peut être coûteux pour les grandes collections. Utilisez des collections indexées telles que List<T> ou des tableaux à cette fin.

+1

Les tableaux dans .NET implémentent déjà 'IList' de sorte que la deuxième surcharge est inutile. – Dai

0

J'utilise ce ExtensionMethod pendant un certain temps:

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

Vous avez oublié d'ajouter une instance de classe aléatoire – bafsar

0

je devais plus élément au lieu d'un seul. Alors, je l'ai écrit ceci:

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; 
} 

Avec cela, vous pouvez obtenir des éléments combien vous voulez que au hasard comme ceci:

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

var randomItemList = _allItems.GetSelectedRandom(10); 
2

Pourquoi ne pas:

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