2010-06-30 19 views
5

Ho un requisito nel mio progetto .net in cui ho bisogno di selezionare un elemento da una collezione, ogni oggetto ha un peso (intero da 1 a 10) assegnato ad esso. Ho bisogno di un generatore casuale che prenda in considerazione questo peso, cioè più alto è il peso, maggiori sono le probabilità che l'oggetto venga selezionato. Sono graditi tutti gli esempi di codice in .net, sebbene la descrizione dell'algoritmo sia piacevole.Ho bisogno dell'algoritmo casuale con opzioni di pesatura in .net

Modifica: copia/incolla il codice C# nel caso in cui qualcuno si imbatta in questo.

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

Non si vuole essere la creazione di un nuovo caso ogni chiamata a 'GetRandom'. Il costruttore predefinito di 'Random' semina il generatore con il tempo di attività del sistema in millisecondi. Se chiami il tuo 'GetRandom' più di una volta al millisecondo, ti verrà restituito lo stesso valore. Anche se non lo fai, potresti restituire risultati che hanno una "casualità" peggiore rispetto al semplice riutilizzo di una singola istanza 'Random'. – Dolphin

risposta

8

Ecco un algoritmo che non richiede l'aggiunta di più elementi a un elenco. Può funzionare anche con pesi non interi, anche se stai usando NextDouble da System.Random, dovrai scalare tutti i pesi per aggiungere fino a 1 o moltiplicare il valore da NextDouble con S per ottenerlo l'intervallo desiderato.

data una lista L di articoli (I, W), dove I è l'oggetto e W è il peso:

  1. aggiungere tutti i pesi insieme. Chiama questa somma S.
  2. Genera un numero casuale compreso tra 0 e S (escluso S, ma incluso 0). Chiama questo valore R.
  3. Inizializza una variabile su 0 per tenere traccia del totale parziale. Chiameremo questo T.
  4. Per ogni elemento (I, W) in L:
    1. T = T + W
    2. Se T> R, tornare I.
+0

Invece di ridimensionare i tuoi pesi, potresti semplicemente usare 'NextDouble() * S' –

+0

@Justin: Sì, funzionerebbe anche. Ho aggiornato il mio post di conseguenza. –

4

Fare una lista e inserire ogni articolo in Peso numero di volte. Quindi scegli un elemento casuale dall'elenco.

+0

Grazie, è stato semplice :) –

+1

Va notato che questo funziona perché i tuoi pesi saranno sempre interi. –

+0

Sì, questo è un requisito. Il peso sarà sempre intero e almeno 1. Il limite di peso superiore non è importante sembra. –

1

Quello che stai cercando è chiamato l'algoritmo del Selettore Ponderato. In realtà ho creato un progetto C# open source per questo qualche tempo fa!

È molto facile da usare ed efficiente. Inoltre, la documentazione dovrebbe farti andare senza problemi.

Qui ci sono alcuni link: