Estrarre dati casuali da un elenco o tabella.   (29/03/03)

Trovo interessante segnalare un esercizio scaturito da una richiesta ricevuta : l'estrazione casuale di nomi, (propri, di città, di animali, di piante, ecc.ecc.), ma vale anche per l'estrazione di numeri. Mentre per i numeri la Funzione ROUND() è specifica, proprio perchè valori numerici, per i nomi (o comunque testo o date) bisogna creare un Indice (e quindi un numero) che identifichi un determinato valore in formato testo o data. Potremmo creare degli Array i quali restituiscono il valore dichiarato in funzione dell'indice rappresentato, ma sceglieremo una strada diversa, che ci consenta di poter modificare non solo il nostro testo come più ci piace, ma di decidere a piacere da quante parole sarà formato il nostro elenco. Useremo quindi o una sola colonna dove scrivere, riga dopo riga, le parole che vorremo randomizzare creando un elenco o tabella, oppure più righe e più colonne per avere una tabella ancora più ampia. In questo modo con il numero di riga e/o di colonna, avremo i nostri numeri da poter randomizzare. Vediamo quindi i passaggi dei due casi.

Area posta su una sola colonna, la colonna A che è la prima

  • identificazione dell'area che contiene i dati; con UsedRange identifichiamo l'area qualunque sia la lunghezza.

Set zona = ActiveSheet.UsedRange

  • trovare da quante righe è formata l'area così reperita, ed assegnazione del valore numerico ad una variabile ( la x )

x = zona.Rows.Count

  • (*)estrazione di un numero casuale compreso tra 1 ed il valore che la variabile x conterrà; poichè per il vba i numeri partono da zero (e noi non avremo una riga zero, ma partiremo sempre da riga uno), aggiungiamo  + 1 al valore casuale estratto (infatti, supponendo di avere 50 righe, in realtà l'intervallo sarebbe da zero compreso a quarantanove compreso, che fanno appunto 50 numeri). Il valore numerico così trovato rappresenterà il numero di riga. Questo valore lo assegnamo ad una variabile (quale)

quale = Int(x * Rnd) + 1

  • ora preleviamo con un'altra variabile ( la Y ) il valore presente nella cella rappresentata dalla riga quale indicando la colonna 1 ( Cells(quale, 1), supposto di avere l'elenco nella colonna A ) che sarà un nome, e formiamo un messaggio che mostrerà il nome così trovato.

Y = Cells(quale, 1).Value
MsgBox Y

  • Precisazione: se l'elenco fosse invece in un'altra colonna, la C per esempio ( che è la numero 3 ) dovremmo nell'istruzione sopra descritta, indicare con 3 l'indice colonna, così:

  • Y = Cells(quale, 3).Value

Per evitare la ripetitività nella sequenza dei valori restituiti dovremo adoperare la funzione Randomize che utilizza numero per inizializzare il generatore di numeri casuali della funzione Rnd assegnandogli un nuovo valore. Se numero viene omesso, il valore restituito dal timer di sistema verrà utilizzato come nuova base.
Se Randomize non viene utilizzata, quando la funzione Rnd (senza argomenti) viene chiamata per la prima volta, utilizza come base lo stesso numero. Per le chiamate successive la funzione utilizzerà l'ultimo numero generato.
 

E questa la routine:

Sub Acaso()
Set zona = ActiveSheet.UsedRange
x = zona.Rows.Count

Randomize
quale = Int(x * Rnd) + 1
Y = Cells(quale, 1).Value
MsgBox Y
End Sub

Se invece la tabella sarà stata creata su più colonne, sempre supponendo di avere l'inizio elenco nella colonna A (la prima) avremo bisogno di contare anche da quante colonne è formata , sempre rintracciando la nostra area con l'UsedRange, con queste modifiche:

z = zona.Columns.Count

e di creare una casualità anche per le colonne, con:

dove = Int(z * Rnd) + 1

e di reperire quindi un indice cella che oltre al numero di riga porterà anche il numero di colonna, con

Y = Cells(quale, dove).Value

ed alla fine la routine completa in questo caso sarà:

Sub Acasodue()
Set zona = ActiveSheet.UsedRange
x = zona.Rows.Count
z = zona.Columns.Count

Randomize
quale = Int(x * Rnd) + 1
dove = Int(z * Rnd) + 1
Y = Cells(quale, dove).Value
MsgBox Y
End Sub

ATTENZIONE: tutte queste routine si basano su una tabella che inizi dalla riga 1 e dalla colonna A. La variabile Y identifica il numero di riga e di colonna generati dalla randomizzazione, e quindi numeri casuali compresi tra 1 e il numero di righe e di colonne che formeranno la nostra tabella. Poichè l'istruzione Cells (Cells(quale, dove).Value) usata su un foglio di lavoro inizia a contare dalla prima cella (la A1) per trovare la cella Y rappresentata dai valori  quale e dove,  SE LA TABELLA iniziasse dalla riga 3 e dalla colonna C (anch'essa la numero 3), avremo bisogno di aggiungere questi numeri (3 e 3) al numero indice che serve a generare il numero casuale. Il motivo di ciò è anticipato al punto con l'asterisco rosso (*) più sopra, e quindi le nostre istruzioni verrebbero modificate su queste due righe:

quale = Int(x * Rnd) + 4
dove = Int(z * Rnd) + 4

anzichè

quale = Int(x * Rnd) + 1
dove = Int(z * Rnd) + 1

Infatti, sempre rifacendo l'esempio delle 50 righe, avremmo bisogno di partire dalla riga 3, e quindi avremo 3 righe, + 1 per correggere l'indice zero, = 4. in questo modo otteniamo che se la randomizzazione del valore 50 (rappresentato da x) generasse zero, avremo 0 + 4 che indica la riga 3, se invece il numero casuale generato fosse 49 (limite superiore del valore 50 visto con inizio da zero), il numero di riga corrispondente sarebbe 53. Lo stesso vale per l'indice colonna se la colonna fosse la C.

Spero di essere stato sufficientemente chiaro.
Buon lavoro.


prelevato sul sito http://ennius.interfree.it