2010-06-30 16 views
5

J'ai un besoin dans mon projet .net où je dois sélectionner un élément d'une collection, chaque élément a un poids (entier de 1 à 10) qui lui est assigné. J'ai besoin d'un générateur aléatoire qui prendrait ce poids en considération, c'est-à-dire, plus le poids est élevé, plus il y a de chances que l'objet soit sélectionné. Tous les exemples de code dans .net sont appréciés, bien que la description de l'algorithme soit agréable aussi.J'ai besoin d'un algorithme aléatoire avec des options de pesage en .net

Editer: Copier/coller rapidement le code C# au cas où quelqu'un trébucherait dessus.

class RandomWeightedSelector<T> 
    { 
     private List<T> items = new List<T>(); 

     public void Add(T item, uint weight = 1) 
     { 
      for (int i = 0; i < weight; i++) 
       items.Add(item); 
     } 

     public T GetRandom() 
     { 
      return items[new Random().Next(0, items.Count)]; 
     } 
    } 
+1

Vous ne voulez pas être la création d'un nouveau chaque appel aléatoire 'GetRandom'. Le constructeur par défaut de 'Random' ensemence le générateur avec le temps de fonctionnement du système en millisecondes. Si vous appelez votre 'GetRandom' plus d'une fois par milliseconde, vous obtiendrez la même valeur. Même si vous ne le faites pas, vous pourriez renvoyer des résultats qui ont un «caractère aléatoire» pire que de simplement réutiliser une seule instance de 'Random'. – Dolphin

Répondre

8

Voici un algorithme qui ne nécessite pas d'ajouter plusieurs fois les éléments à une liste. Il peut également fonctionner avec des poids non entiers, bien que si vous utilisez NextDouble de System.Random, vous devrez mettre à l'échelle tous les poids pour ajouter jusqu'à 1, ou multiplier la valeur de NextDouble par S pour l'intégrer. la gamme désirée.

donné une liste d'articles L (I, W), où I est l'élément et W est le poids:

  1. Ajouter tous les poids ensemble. Appelez cette somme S.
  2. Générer un nombre aléatoire entre 0 et S (sauf S, mais en incluant 0). Appelez cette valeur R.
  3. Initialisez une variable à 0 pour garder trace du total cumulé. Nous appellerons T.
  4. Pour chaque élément (I, W) en L:
    1. T = T + W
    2. Si T> R, retour I.
+0

Au lieu de mettre à l'échelle vos poids, vous pouvez simplement utiliser 'NextDouble() * S' –

+0

@Justin: Oui, cela fonctionnerait aussi. J'ai mis à jour mon message en conséquence. –

4

Faites une liste et insérez chaque élément dans Poids nombre de fois. Choisissez ensuite un élément aléatoire dans la liste.

+0

Merci, c'était simple :) –

+1

Il convient de noter que cela fonctionne parce que vos poids vont toujours être des entiers. –

+0

Oui, c'est une exigence. Le poids sera toujours entier et au moins 1. Le poids supérieur n'est pas important, semble-t-il. –

1

Ce que vous cherchez s'appelle l'algorithme du sélecteur pondéré. J'ai créé un projet C# open source pour ça il y a quelque temps!

C'est très facile à utiliser et efficace. En outre, la documentation devrait vous permettre de démarrer sans problème.

Voici quelques liens: