J'ai une liste de tableaux et je dois pouvoir cliquer sur un bouton, puis sélectionner au hasard une chaîne de cette liste et l'afficher dans une boîte de message.
Comment pourrais-je m'y prendre?
Créez une instance de Random
class quelque part. Notez qu'il est très 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 uniformiser les nombres générés. Vous pouvez avoir un champ static
quelque part (faites attention aux problèmes de sécurité des threads):
static Random rnd = new Random();
Demandez à l'instance Random
de vous donner un nombre aléatoire avec le nombre maximal d'éléments dans la ArrayList
:
int r = rnd.Next(list.Count);
Afficher la chaîne:
MessageBox.Show((string)list[r]);
J'utilise habituellement 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ée, cela vous permettrait d'écrire:
var strings = new List<string>();
var randomString = strings.PickRandom();
Si tout ce que vous avez est une ArrayList, vous pouvez le lancer:
var strings = myArrayList.Cast<string>();
Tu peux faire:
list.OrderBy(x => Guid.NewGuid()).FirstOrDefault()
Créez une instance Random
:
Random rnd = new Random();
Récupérer une chaîne aléatoire:
string s = arraylist[rnd.Next(arraylist.Count)];
Rappelez-vous cependant que si vous le faites fréquemment, vous devez réutiliser l'objet Random
. Mettez-le comme un champ statique dans la classe pour qu'il ne soit initialisé qu'une fois, puis y accéder.
Ou une classe d'extension simple comme celle-ci:
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)];
}
}
Alors appelez simplement:
myList.RandomElement();
Fonctionne aussi pour les tableaux.
J'éviterais d'appeler OrderBy()
car cela peut coûter cher pour de plus grandes collections. Utilisez des collections indexées comme List<T>
ou des tableaux à cette fin.
Pourquoi pas:
public static T GetRandom<T>(this IEnumerable<T> list)
{
return list.ElementAt(new Random(DateTime.Now.Millisecond).Next(list.Count()));
}
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());
J'avais besoin de plus d'articles au lieu d'un seul. Donc, j'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 autant d'éléments que vous le souhaitez au hasard:
var _allItems = new List<TModel>()
{
// ...
// ...
// ...
}
var randomItemList = _allItems.GetSelectedRandom(10);
J'utilise cette extensionMethod depuis un moment:
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;
}