Newsgroup: it.comp.www.php
Titolo: do i numeri

Salve,
dato il range 0,80
non trovo il modo di generare n numeri interi UNIVOCI compresi tra 0 e 
80 (per esempio 1,4,5,6,8, non 1,1,2,2,3).
Ho letto nella documentazione ed ho trovato l'utile funzione rand.
In teoria, per ottenere 1 numero posso fare rand(0,80).
Quando però chiamo il random la seconda volta, nulla impedisce al rand 
di estrarre un numero precedentemente estratto.
Come potrei risolvere? Grazie a tutti   :-)

function random_number_array($count, $from, $to){
    for($i=$from;$i<$to;$i++){
    $number_array[] = $i;
    }
    $random_number_array = array();
    mt_srand ((double) microtime() * 1000000);
    for($i=0;$i<$count;$i++){
      $random_number            = mt_rand(0,count($number_array)-1);
      $key_to_insert_and_delete = array_search($random_number, 
$number_array);
      $random_number_array[$i]    = 
$number_array[$key_to_insert_and_delete];
      array_splice($number_array, $key_to_insert_and_delete, 1);
    }
    // Array $random_number_array with $count random Numbers, between 
$from and $to
    return $random_number_array;
}
(la guida va letta meglio!)


Come può un sistema generare numeri univoci se non sà che numero ha 
precedentemente generato?
Indi per cui puoi utilizzare le funzioni random ma devi gestire uno 
storico dei numeri precedentemente generati, però con la crescita dello 
storico aumenterà anche il tempo di generazione del nuovo numero quindi, 
  la soluzione più semplice, sempre se per te va bene, è generare prima 
n-mila numeri random e pescare dalla "pila" dei numeri precedentemente 
generati (ovviamente in ordine progressivo).
	Francesco

 ha scritto nel messaggio 
news:4731ec5e$0$4789$4faf...@reader4.news.tin.it...

------------
se $numero[$numero_casuale] non è impostato... fai....ecc. ecc.
 

generati (ovviamente in ordine progressivo).
Che non da il risultato richiesto...
La soluzione che poi è quella usata per mischiare un mazzo di carte ad
esempio è:
1) prepari un array con dimensione desiderata e riempita coi valori
desiderati nel nostro caso un array di 80 elementi con i numeri da 1 a
80
2) inizializzi un contatore i = 80
3) generi un numero casuale fra 1 e i
4) iesimo elemento dell'array lo usi e poi lo elimini dall'array
compattandolo e dimnuisci i di 1 oppure scambi l'elemnto con iesimo
elemento (se vuoi usare nuovamente l'array e decrementi i di 1
5) cicli fra 3 e 4 sino ad aver estratto tutti i numeri i=0
COn questo sistema estrai casualmente da un elenco di lunghezza data
gli N elementi desiderati tenendo conto delle estrazioni già
effettuate, il vantaggio è che gli elementi potrebbero essere numeri,
stringhe etc etc
-- 
Stefano Aglietti - StallonIt on IRCnet - ICQ#: 2078431
Email: 
st...@40annibuttati.it
 
ste...@people.it
Sites: 
http://www.40annibuttati.it
 (personal blog)
 
http://www.wordpress-it.it
 (WordPress Italia)

 
Per quale motivo? Ovviamente nella mia frase "è generare prima n-mila 
numeri random" si sottointende il controllo dell'univocità dei dati.
	Francesco

dirtysomething ha scritto:

Uhm, uhm... per prima cosa ti dirò secondo me come NON farlo (qua 
sotto): prima di tutto la funzione potrebbe avere prestazioni 
*scarsissime* se non addirittura piantarsi (immagina il caso in cui 
tutti i numeri tra $min e $max siano già stati estratti), inoltre 
l'array $past potrebbe crescere indefinitamente e contenere valori 
inutili...
function unirand1($min, $max)
{
	static $past = array();
	while(in_array(($new = rand($min, $max)), $past));
	array_push($past, $new);
	return $new;
}
In quest'altro caso invece l'idea di base è che ogni volta che la 
funzione viene chiamata con nuovi limiti oppure esaurisce le 
possibilità, si autogenera un array con tutti i numeri che potrebbero 
uscire e li mette in ordine sparso. Ad ogni chiamata successiva con gli 
stessi limiti estrae un numero dalla lista. Decisamente più stabile e 
soprattutto è garantito che non si pianti. Ovviamente avendo un range 
tra 0 e 80 puoi chiamare la funzione 81 volte prima che i numeri inizino 
a ripetersi.
function unirand2($min, $max)
{
	static $s_min = -1;
	static $s_max = -1;
	static $s_nums = array();
	// if we have new limits
	if($s_min != $min || $s_max != $max || !count($s_nums))
	{
		// init limits
		$s_min = $min;
		$s_max = $max;
		// create numbers
		$s_nums = range($s_min, $s_max);
		shuffle($s_nums);
	}
	// return next number
	return array_pop($s_nums);
}
Probabilmente qualcuno ha un'idea migliore =) Ma quantomeno questa 
funziona! Ciao

 nulla impedisce al rand di estrarre un numero precedentemente estratto.
$n = 5;
$a = array_fill(0,80);
$randoms = array_rand($a, $n);
Bye.

numeri random" si sottointende il controllo dell'univocità dei dati.
Ok da il risultato richiesto... ma... supponendo di dover "estrarre"
che ne so 10.000 voci (nota voci non solo numeri) tu prima genereresti
se va bene, e dubito, 10 volte tale numero, per ciascuno controlli se
non è già stato estratto e poi alla fine usi il tuo array per simulare
l'estrazione? Si può pure fare ma sei sicuro che uno dei 10.000 numeri
richiesti non appaia che ne so solo dopo 10.000.000 di registrazioni?
Pur essendo la funzione di randomizzazione i PHP un generatore
pseudorandom nessuno ti garantisce che non accada.
Lo stesso per 80... potrebbero apparire dopo 80.000 generazioni...
risultato magari impieghi 2 minuti per generare la lista e 1,5 sec per
fare l'estrazione alla faccia dell'ottimizzazione :)
L'algoritmo da me proposto è utilizato normalmente e h il vantagggio
di impiegare sempre lo stesso tempo di calcolo, dare il medesimo
risultato, essere codificabile in maniera decisamente più semplice e
poter operare non solo su insiemi di numeri (che potrebbero anche nn
essere in sequenza) ma su qualsiasi genere di tipo dati.
Poi vedi tu...


 $randoms = array_rand($a, $n);
Ma quanto è figo il PHP?
-- 
Jax

 Bye.
Alessandro (ne approfitto comunque per ringraziare tutti quelli che si 
sono appassionati al tema), GRAZIE.
All'inizio non mi funzionava, ho letto poi la guida e ho "corretto" così:
$n = 5;
$a = array_fill(0,80,--->0);
$randoms = array_rand($a, $n);
print_r($randoms);
Bye!

 
Forse non sono stato molto chiaro, mi scuso e cerco di rimediare.
Se devo utilizzare un contatore "random", ovvero un valore 
(numero/stringa/oggetti) che abbia i requisiti di random e univico, la 
mia soluzione era di popolare a priori una pila (implementata p.esempio 
come tabella di db), rispettando univocità e casualità e attingere da 
questa pila un elemento alla volta, per restare nella logica del db, 
marcando ogni record come estratto. In questo modo non ho in memoria un 
array composto da n-mila valori e posso, al bisogno, ripopolare la mia 
pila aggiungendo nuovi record etc.
Ovviamente se l'utente ha la necessità di generare one-time n (pochi) 
numeri casuali e univoci vanno bene le soluzioni su array, se si tratta 
di generare un token univoco per attribuirlo ad un link per un download, 
come id di un record o cose del genere, non vedo altre soluzioni, 
ammesso che non voglio generare un numero random, vedere se già usato, 
in tal caso rigenerarlo e riprocedere con il controllo.
	Francesco

 print_r($randoms);
$numbers = range(0, 80);
shuffle($numbers);
foreach ($numbers as $number) {
   echo "$number ";
}
Comunque di modi ne esistono davvero tanti, più o meno complessi.
-- 
rob4you
www.outofmind.eu

 Comunque di modi ne esistono davvero tanti, più o meno complessi.
Infatti. Questi vanno benone quando devi farlo per 100 o 1000 numeri, ma 
quando devi estrarne 5 da un range di un milione ci sono alternative piu` 
valide.
In pratica vanno valutate le complessita` dei problemi e scelto 
l'algoritmo migliore. :)
Bye.


Potresti inizializzare un vettore con tutti gli elementi del range, e
poi fare uno shuffle.
Ovvero:
--------------------------------------------
$inizio = 0;
$fine = 80;
// Inizializzo il vettore
$arrValori = array();
for ($k=$inizio;$k<=$fine; $k++)
{
      $arrValori[] = $k;
}
// Mischio il vettore
shuffle($arrValori);
// Stampo i valori casuali;
foreach($arrValori as $valore)
{
       echo $valore."<br>";
}
-------------------------------------------
Ciao,
      Fabrizio