PDA

Ver la Versión Completa : Función Random ???


BlueSteel
16-06-2008, 22:11:19
Hola...

tengo algunas dudas con respecto al uso de la función Ramdon. La estoy implementando para que me escoga el ganador de un concurso, en donde tiene que elegir un numero al azar de un universo de 1503.

La estoy utilizando de esta forma


sGanador.Text := IntToStr(Random(1503));


Si bien, el proceso lo realiza y me muestra valores aleatoreos que no sean mayores de 1503, el problema es el siguiente:

1.- cada vez que inicio el sistema, el primer valor que selecciona es 0, despues 47, despues 1294, despues 304... por lo cual, no me estaria sirviendo dicha función, ya que siempre que ingrese al sistema estarían eligiendo los mismos numeros y en el orden que los deje. Puede que sea un parametro que obvie, pero igual me causa extraseña

2.- necesito que la aplicación me seleccione los valores al azar, pero que no me salga favorecido un valor que ya ha sido seleccionado, es decir, si en el sorteo 1 salio de 15, que no se repita dicho numero en ninguno de los siguientes sorteos...

Bueno, el concurso consiste en regalar 300 camisetas del Club de Fútbol, 20 Televisores Plasta de 32" y un Auto 0 KM, por lo cual, y como es ante Notario, no pueden repetirse los numeros...

que me sugieren que realice...???

Salu2:p:D

Black_Ocean
16-06-2008, 23:20:17
Hola,

Antes de usar la función Random debes inicializarlo con el procedimiento Randomize para que no se repitan los números en forma seguida.

Ej:

Randomize;
Random(1503);


Por otra parte, te recomiendo que uses la función RandomRange de la librería Math en reemplazo de Random, ya que puedes definir el rango desde y hasta qué número deseas, y tambien por si no quieres considerar el 0, ya que Random considera de acuerdo a esta condición: 0 <= X < Rango

Saludos y buena suerte colega.

BlueSteel
16-06-2008, 23:41:10
Ok...

Muchas Gracias...

Ya me funciona tanto con el Ramdon (agregando el randomize...y con el RandomRange...

Salu2:p:D

BlueSteel
17-06-2008, 00:32:18
Bueno, para no hacer otro hilo, solo me falta ver la opción de que no seleccione un numero que ya se ha seleccionado...

Alguien sabes como se puede realizar esto ???

Salu2:p:D

eduarcol
17-06-2008, 00:49:32
pues para eso deberias tener una lista, y hacer algo asi:

while x in Lista do

BlueSteel
17-06-2008, 01:00:38
pues para eso deberias tener una lista, y hacer algo asi:


Código Delphi [-] (http://www.clubdelphi.com/foros/#)while x in Lista do




si estaba pensando algo parecido.... bueno, los favorecidos los voy metiendo en una tabla temporal.... donde tambien almaceno el numero sorteado.....

así que tendré que ir comparando si el numero esta dentro de los ya favorecidos.... lo que me da lata es que puede demorarse mucho en recorrer la tabla, ya que los registros de la tabla temporal se van insertando según posición de llegada, por lo que tendre que verificar toda la tabla cada vez que salga un numero nuevo.... y debo generar un listado de 300 ganadores....??

bueno, ahora es muy tarde....así que me voy a jugar unas mesitas de billar para relajarme.. y mañana veré como lo realizo...

Salu2

Black_Ocean
17-06-2008, 01:20:31
Hola,

Para almacenar datos temporales para este caso como el tuyo, lo más cómodo es trabajar con conjuntos. Delphi implementa esto de una manera muy simple, ya que es el mismo concepto que los conjuntos cuando te los enseñan en básica =).

Aquí te pongo un ejemplo de cómo trabajar con conjuntos en Delphi.

type
TSelecciones = set of 1..255; // esto se refiere a que el conjunto puede contener números desde el 1 hasta el 255

var
Seleccionados: TSelecciones;

procedure TForm1.Button1Click(Sender: TObject);
begin
Seleccionados := [1, 2, 3]; //inicializamos el conjunto con estos 3 numeros cualquieras que los contendrá

if not (4 in Seleccionados) then //chequeamos si el 4 está contenido en el conjunto, como no está, devuelve falso
ShowMessage('No está el número en el conjunto :-(');

Seleccionados := Seleccionados + [4]; //Agregamos al conjunto el número 4 (ahora contendrá el 1, 2, 3 y el 4)

if 4 in Seleccionados then // Ahora como el conjunto aparte de los 3 números iniciales contiene tambien el 4 devolverá verdadero =)
ShowMessage('Ahora está el número en el conjunto =)');
end;

Saludos y espero que te ayude :)

Caro
17-06-2008, 12:31:31
Hola BlueSteel, también podrías utilizar un StringList y su función IndexOf para buscar si algun número ya esta en la lista, mas o menos sería así el codigo.


Lista : TStringList;
....
....
var
Numero, Limite : Integer;
begin
Randomize;
Limite := 1300;
Numero := Random(Limite);
if Lista.IndexOf(IntToStr(Numero))=-1 then
Lista.Add(IntToStr(Numero))
else
begin
While (Lista.IndexOf(IntToStr(Numero))<>-1) and (Lista.Count<Limite) do
Numero := Random(Limite);

if Lista.IndexOf(IntToStr(Numero))=-1 then
Lista.Add(IntToStr(Numero));
end;


donde Lista es un StringList, ademas que debes crearlo talvez en el OnCreate de tu formulario.

Saluditos

Neftali [Germán.Estévez]
17-06-2008, 12:53:49
...lo que me da lata es que puede demorarse mucho en recorrer la tabla, ya que los registros de la tabla temporal se van insertando según posición de llegada, por lo que tendre que verificar toda la tabla cada vez que salga un numero nuevo.... y debo generar un listado de 300 ganadores....??

Utiliza un TStringList en memoria ordenado. Las búsquedas son dicotómicas y casi inmediatas.
A medida que vayan saliendo buscas y añades los nuevos.

Caro
17-06-2008, 13:10:15
...un TStringList en memoria ordenado.....

Una pregunta Neftalí, esto significa que a parte de usar un TStringList y la función IndexOf, debemos también ordenarlo con Lista.Sorted := True, supongo que cada vez que se haya introducido un número a nuestra lista.

Saluditos

Neftali [Germán.Estévez]
17-06-2008, 13:36:49
Una pregunta Neftalí, esto significa que a parte de usar un TStringList y la función IndexOf, debemos también ordenarlo con Lista.Sorted := True, supongo que cada vez que se haya introducido un número a nuestra lista.

Al crear el stringList lo creas con la propiedad Sorted a True.


TS := TStringList.Create();
TS.Sorted := True;
TS.Duplicates := dupError;


En tu caso yo aseguraría que no hay duplicados, ya sea con dupError o dupIgnore (mejor el primero).

A partir de ahí puedes utilizar IndexOf o Find para encontrar el elemento que necesites. No necesitas reordenar maualmente cada vez.
Al estar ordenada e insertar elementos ya te los añadirá ordenados. Es un poco más lento al insertar/borrar, pero infinitamente más rápido al buscar.

Caro
17-06-2008, 13:49:20
Me ha quedado claro Neftali, muchas gracias por responderme.

Saluditos

BlueSteel
17-06-2008, 20:13:11
Hola Caro

Muchas gracias por tu respuesta...

me da error aquí ??? estará bien esto o le falta algo ???

While (Lista.IndexOf(IntToStr(Numero))<>-1) and (Lista.Count

Lo otro es que nunca he usado un StringList, así que desde donde saco el componente (pestaña del delphi 7.. bueno si es que es un componente)... o solo se declara por código...

Salu2:p:D

maeyanes
17-06-2008, 20:40:47
Hola...

Un TStringList no es un componente, es una clase, la cual está declarada en la unidad Classes...

Y recuerda, tienes que decir que error es el que te da, para que te podamos ayudar...

Hasta pareces nuevo... :D :D :D


Saludos...

BlueSteel
17-06-2008, 21:00:15
Bueno...

al final lo realice de otra forma... sin crear un StringList...:D


Procedure TForm1.Sortear;
Var
Num_Registros : Integer;
sFin : Boolean;
begin
sFin := False;
Num_Registros := ADQ_Select.RecordCount;
Randomize;

While sFin = False Do //Ciclo para verificar si el numero ya habia sido seleccionado
Begin
sGanador.AsInteger := RandomRange(1,Num_Registros);
With Premiados Do
Begin
If Not Locate('Nro',sGanador.Text,[]) Then // Aqui verifico que no este dentro de la tabla temporal.. si no esta lo agrego..
Begin
ADQ_Select.Locate('Nro',sGanador.Text,[]);
Premiados.Append;
Premiados.FieldByName('Nro').AsString := IntToStr(ADQ_Select['Nro']);
Premiados.FieldByName('Rut').AsString := ADQ_Select['Rut'];
Premiados.FieldByName('Nombre').AsString := Concat(ADQ_Select['Nombres'],' ',ADQ_Select['Apellidos']);
Premiados.FieldByName('Contrato').AsInteger := ADQ_Select['Contrato'];
Premiados.FieldByName('Abono').AsInteger := ADQ_Select['Abono'];
Premiados.FieldByName('Ubicacion').AsString := ADQ_Select['Ubicacion'];
Premiados.Post;
sFin := True;
End;
End;
End;
end;


bueno, y el codigo anterior lo llamo así


procedure TForm1.BitBtn4Click(Sender: TObject);
Var
i : Integer;
begin
For i:=1 to 300 Do
Begin
Sortear;
End;
end;



Bueno, el proceso en si se demora alrededor de 2 segundos en seleccionar los 300 numeros de un universo de 1505... así que quede más que satisfecho con el código...:D

maeyanes
tines toda la razón.. no di el código ni mensaje de error... creo que yo mismo me enviaré a leer la guia de estilo.. :p y como penitencia realizaré 1000000 de.. debo entregar codigo de error:D:D:D

For i:=1 to 1000000 Do
ShowMessage('Debo engregar el error completo, con código y mensaje de error... no volverá a pasar de nuevo');



Salu2:D:D:D

maeyanes
17-06-2008, 21:36:45
Hola...

Con un TStringList podría quedar más o menos así:


function Sortear: TStringList;
const
NoGanadores = 300;
NoParticipantes: 1505;

var
I: Integer;
Ganador: Integer;

begin
Randomize;
Result := TStringList.Create;
Result.Sort := True;
for I := 1 to NoGanadores do
begin
Ganador := RandomRange(1, NoParticipantes);
if Result.Count = 0 then
Result.Add(IntToStr(Ganador))
else
begin
while Result.IndexOf(IntToStr(Ganador)) <> -1 do
Ganador := RandomRange(1, NoParticipantes);
Result.Add(IntToStr(Ganador))
end
end
end;

// Para usar la función:

var
ListaGanadores: TStringList;

begin
ListaGanadores := Sorteo;
// Usas la lista
ListaGanadores.Free
end;



Saludos...

Caro
18-06-2008, 02:57:25
Hola BlueSteel, yo sigo pensando que deberías hacerlo con StringList, no es dificil manejarlo.

Un StringList es una clase que hereda de TString, llegando a ser una lista de cadenas que la tienes en memoria. como dice Neftali las búsquedas son casi inmediatas, de verdad te ayudara mucho en otras cosas que quieras hacer, incluyendo esta.

Sobre el error en la linea que marcas le faltaba un parentesis al final, se me ha ido.

Primero debes definir una variable de tipo TStringList y despues crearla como cualquier instancia de clase con:


StringList : TStringList
......
StringList := TStringList.Create;


Despues puedes utilizar todas las funciones y procedimientos de la clase TString como Add, Delete, IndexOf, Exchage..... Si te fijas en el componente ListBox, existe una propiedad Items, que es un TString, y seguro que sabes manejar dicha propidad adicionando items, borrando, etc, un TStringList lo manejas de la misma manera ya que también hereda de TString, la diferencia es que no es un componente sino solo una clase.

Ahora sobre mi ejemplo quedaría así, seleccionando los 300 ganadores.


procedure TForm1.Button1Click(Sender: TObject);
var
Numero, i, j, Limite : Integer;
Lista : TStringList;
begin
Lista := TStringList.Create;
Lista.Sorted := True;

Randomize;
Limite := 1500;
for j:=0 to 300 do
begin
Numero := RandomRange(0, Limite);
if Lista.IndexOf(IntToStr(Numero))=-1 then
Lista.Add(IntToStr(Numero))
else
begin
While (Lista.IndexOf(IntToStr(Numero))<>-1) and (Lista.Count<Limite) do
Numero := RandomRange(0, Limite);

if Lista.IndexOf(IntToStr(Numero))=-1 then
Lista.Add(IntToStr(Numero));
end;
end;

showmessage('Se ha terminado de encontrar a los ganadores');

for i :=0 to Lista.Count-1 do //Recorremos la lista
showmessage(Lista[i]);
end;


Saluditos

Caro
18-06-2008, 03:11:48
Hola de nuevo, el error que te marcaba no es por un parentesis al final, nose porque me corta esa linea y no se muestra completo esto es lo que puse en esa condición "While (Lista.IndexOf(IntToStr(Numero))<>-1) and (Lista.Count<Limite) do"

Saluditos

Delphius
18-06-2008, 05:44:27
Yo también considero de que el uso de TStrinList es una opción recomendable. Cuenta con los métodos adecuados para resolverte el problema de buscar entre los repetidos. Ni que decir de que con emplear el TStringList te evitas tener que estar buscando contra la base de datos y luego guardando.

Por otro lado, si es demasiado preocupante el tema de los repetidos y te resulta un tanto "molesto" el emplear un TStringList, te recomendaría que emplearas algún generador de números pseudoaletorios que te grantize de que no habrá ningún repetido en una serie de m elementos (ese m es número bastante enorme por cierto).

Existen. Si que existen. Los generadores que cumplen con estas condiciones son los generadores congrenciales (http://es.wikipedia.org/wiki/Generador_de_n%C3%BAmeros_aleatorios) mixtos.

Para que exista esta característica en dichos generadores se debe cumplir estos requisitos:
1. b es primo con m
2. a-1 es múltiplo de p para todo primo p que divida a m
3. a-1 es múltiplo de 4 siempre que m sea múltiplo de 4

Para comprender mejor el tema te hago llegar este documento (http://www.ing.ula.ve/%7Ehhoeger/simulacion/PARTE4.pdf).
Mis apuntes de Modelos y Simulacones están el armario, perdona que no pueda explayarme demasiado.

Internamente, la función Random es un generador congruencial (o multiplicativo) mixto. Y no me extraña que sus valores a,b y m sean los adecuados según dicho axiomas.
Aunque no está demás hacer algunas comprobaciones. Y no es de extrañar que ante un período m corto como es el de 1503 existan colisiones.

Si buscas sobre el tema en los foros llegarás a hilos en donde he expuesto el tema. De hecho, ha quedado disponible aqui en los foros mis códigos que pueden ser estudiados y adaptados según tus necesidades.

Si necesitas un riguroso control sobre los repetidos puede que debas consideras que la inversión del esfuerzo sobre el de emplear un generador propio (tal vez) te es más viable que emplear un TStringList y el simple Random.

En fin, es una alternativa más que te ofrezco.

Por otro lado, me parece que es más efectivo emplear un repeat-until que un while para iterar hasta encontrar un número que no esté repetido.

El algoritmo debe venir así:

Si empleamos el StrinList
1. Desde 1 hasta CANTIDAD_DE_SORTEOS hacer:
1.1. repetir
1.1.1 Numero = Random(....)
1.1* hasta Numero no esté en lista (si empleamos el uso de un TStringList)
1.2. Añadir a lista
2. Guardar el contenido de lista en DB

Si se opta por emplear el uso de un generador que nos garantize que en el período no exista un repetido entonces lo hacemos más simple así:
1. Desde 1 hasta CANTIDAD_DE_SORTEOS hacer:
1.1. Numero = Random(....)
1.2. Guardar en DB

En fin. Cada cosa que te ofrece sus ventajas y desventajas.

Ahora pienso que, se puede emplear Random() y no random(1503) por ejemplo. Creo (no aseguro) que el uso de Random (sin indicar rango) fuerza al generador a trabajar con el valor máximo de m. Si es así, y si se cumplen estos axiomas mencionados podría bastar con obtener la parte decimal de dicho número y obtener el resto de la divsión respecto a 1503 (tal vez 1504).

Es decir que si obtenemos 0,48971 realizamos estos pasos:
1. Nro = 48971
2. Nro = Nro mod 1503 = 875

¿Porque el mod? Porque de este modo garantizamos que el máximo valor a obtenemos sea menor a 1503.

Ummm.... ¿Y no es eso volver a amplicar un generador sobre otro? Pues de hecho si... volvemos a lo mismo. Ya que de por sí, el generador realizar el mod de un número astronómicamente grande respecto a un valor m (también astronómicamente grande).

En definitiva.... es volvemos a lo mismo. Acotar un rango amplio a uno más bajo. De cualquier manera la distribución de probabilidad que siguen es, un principio, uniforme: 1/m.

Analicemos el tema numéricamente,

Si m es 1503, obtendremos = 0.000665335

Un valor bajo, al menos en un principio. Analizarlo al extremo en el contexto de los 300 Pues.... 300/1503 = 0.1996007984

¿Porqué hice ese 300/1503? Pues para demostrar la probabilidad de que un número se repita 300 veces dentro de los 1503.

Si nos basamos en que el rango de 1503 es corto... yo diría que las probabilidades no son alentadoras. Trabajar con dicho rango es posiblemente, inviable.

Apliqué este algoritmo:


resourcestring
msgSorteado = 'Nro ganador: %d, sorteo nº: %d';

procedure TForm1.RealizarSorteo(Sorteos: TStrings);
const
CANTIDAD_SORTEOS = 300;
var
i, Nro: integer;
begin
Sorteos.Clear;

for i := 1 to CANTIDAD_SORTEOS do
begin
Nro := Random(1503) + 1;
Sorteos.Add(Format(msgSorteado,[Nro,i]))
end;
end;


En un TListBox con la propiedad Sorted en true.

He hecho una prueba con D6 y obtenido repetidos, en distintas iteraciones. De hecho varios números se repiten dos veces.

La prueba no tiene sentido si uno aplica un Randomize obviamente.

La misma prueba, aplicando este algoritmo:

procedure TForm1.RealizarSorteo(Sorteos: TStrings);
const
CANTIDAD_SORTEOS = 300;
var
i, Nro: integer;
begin
Sorteos.Clear;
for i := 1 to CANTIDAD_SORTEOS do
begin
Nro := Trunc(Random * 100000000000) mod 1503;
Sorteos.Add(Format(msgSorteado,[Nro,i]))
end;
end;

Si bien no obtengo toda la parte decimal convertida en entero, para un experimento puede servir.

Y vuelvo a obtener repetidos...
¿Que pasa aquí?
Pues simplemente que estamos acotando el rango grande a uno pequeño.

Realizando la prueba con un Random solo, y un format a 0.8f. No he conseguido ningún repetido.

He aquí la eterna pregunta ¿Nos conformamos con el uso de una "lista" para buscar repetidos e iteramos mientras haya repetidos o nos esforzamos a buscar aquellas propiedades a,b que garantizen junto a m que en la serie no nos vamos a topar con repetidos y empleamos nuestro propio generador?

Puedes probar bibliotecas científicas para ver si alguna ofrece una mejor alternativa.

Y antes yo sacaba valores respecto a 1503.... en realidad amigo, deberíamos hacerlo en 300. Que son en realidad esos 300 números que saldrán. De hecho, si sabemos que en realidad sorteamos 300 numéros, tenemos 1/300 de salir ¿No es cierto? 1/300 no da un valor de 0,003333..

Aun así, necesitamos generar números en el rango buscado y por tanto nuestro "m" son y serán esos 1503. Si tomamos todos, o sólo los primeros 300 ya es otra cosa.

Yo me pregunto, si al acotar el rango a 1503 obtenemos muchos repetidos... que podría esperararse si lo hacemos en 300. (No es necesario responderla, no viene al caso... es sólo una reflexión mia).

Yo hice esos cálculos para mentalizar el porque y cuando el uso de un Random es útil.

Se que no aporto mucho, pero al menos creo que con esto doy un panorama del uso de random.

Recuerden que las implementaciones de Random pueden variar de una versión a otra del compilador.

Saludos

BlueSteel
18-06-2008, 14:44:36
Changos [Delphius]...:eek::eek: que te fumastes :confused::confused: ???

Parece que estos 4 días que no estubistes conectado te tenian atragantado...:D:D

Bueno, revisaré la documentación que dejas.

[Caro], también revisaré lo que me dejastes, no tube tiempo por que salí a realizar compras de partes y piezas, así que creo que en la tarde lo implementaré con TStringList para ver como funciona eso...

Bueno, gracias a todos...

Una última consulta, como puedo forzar a que el Random saque mis 2 numeros para ganarme ya sea una camiseta, un plasma o el auto :D:D

Salu2:p:D

maeyanes
18-06-2008, 14:53:27
Hola...


Programas en la aplicación una combinación de teclas la cual al activarla permita capturar (sin un edit ni nada) el número que tienes asignado... ya que se obtuvo ese número, lo agregas a la lista de ganadores y listo... :D :D :D :D



Saludos...

Delphius
18-06-2008, 15:26:52
Changos [Delphius]... que te fumastes ???

Parece que estos 4 días que no estubistes conectado te tenian atragantado...
Bueno, revisaré la documentación que dejas.

[Caro], también revisaré lo que me dejastes, no tube tiempo por que salí a realizar compras de partes y piezas, así que creo que en la tarde lo implementaré con TStringList para ver como funciona eso...

Bueno, gracias a todos...

Una última consulta, como puedo forzar a que el Random saque mis 2 numeros para ganarme ya sea una camiseta, un plasma o el auto

Salu2:p:D
Amigo Blue, pues.... debo decirte que algo así.
Lo que ha sido estar fuera por 4 días... ha sido dificil soportar esos días sin tocar una PC. El penúltimo dia toqué la noteboock de mi prima, pero donde me encontraba la conexión inalambrica no llega. Supuestamente desde que el gobierno provincial puso internet wifi gratis para toda la provincia no hay un solo punto sin conectar.

Pero que se le va ha hacer... si quería velocidad debía irme a la ruta a la estación de servicio y el acceso al pueblo (justo donde estaba el corte) puesto que en pueblo nadie tiene esa conexión (yo me pregunto... cuantas familias son las que tendrán una PC con una salida a internet). Y el único ciber (en el pueblo) que posee máquinas con acceso a internet lo hace a través de un servicio contratado... Y de por si ese servicio es malo.

Y bueno... me tuve que guardar las ganas.

Revisa esa documentación, a modo de complemento a lo que estuviste haciendo.

Por ahora la opción del TStringGrid es la más recomendable.

Con respecto a la bromita, puedes probar con comprar el número 0 y emplear el generador de Lehmer. Ese generador tiene a cero con algunos valores de m y semillas. Una vez que se estanca en 0, continúa sacando 0 y no sale de allí.:D;) Probabilistamente hablando tienes la probabilidad de jugar por 150 de los premios.:eek::D;)

Saludos,

Caro
18-06-2008, 15:45:29
..............
Por ahora la opción del TStringGrid es la más recomendable.
..............


Creo que si te ha afectado Marcelo, no hemos mencionado sobre el StringGrid, no te preocupes ya te repondrás ;).

Saluditos

maeyanes
18-06-2008, 15:47:07
Eso le pasa por alejarse tanto tiempo del Club... :D :D :D

BlueSteel
18-06-2008, 15:56:39
Eso le pasa por alejarse tanto tiempo del Club... :D :D :D


si se puso así por 4 días, se imaginan a Delphius como con 1 mes o 1 año sin un PC ni siquiera un Celular....:D:D

Salu2:p:D

PS: No desvirtuen los hilos :D:D:D

Delphius
18-06-2008, 16:04:43
:o¡Ouch!:o (Aquí vendría bien el sonido característico de Homero).

No me di cuenta :p
Ando tarugo... no importa, cuando me den cuerda de nuevo me voy a poner mejor.:D;)

A Delphius no me lo imagino, pero si a NewDelphius.:eek::D

Saludos y perdón por el +1,

BlueSteel
04-07-2008, 20:42:13
Hola a todos...

bueno, les cuento que el sorteo ya se realizo.. y que solo alcancé a ganar una Camiseta (http://bluesteel.clubdelphi.com/imagenes/camisetahuachipato.JPG)... con las ganas que le tenia al tucson (http://www.e-renova.net/coches-ocasion/71669_141053.jpg) o a un lcd (http://www.vivelo.cl/VIVELO3/cmsCatalogo.nsf/5775D8D134D5C4D28425708A00620D36/$file/LN26R5.jpg).... pero en fin... la suerte es para quien es... no para el que la desea...

ya.. pasando a otro punto, tube inconvenientes con la funcion que utilice... (que fue la creada por mi...) ya que se me repitieron 62 numeros de los 300 que tenia que obtener... esto se descubrio por que una persona que tenia 1 numero salio favorecido con 2 camisetas y solo podia optar a 1 camiseta.... resumiento a 15 personas le salio el numero duplicado (mismo numero)... y a 5 personas le salio el numero triplicado (mismo numero)....

en fin... probaré las funciones que me dejaron maeyanes y caro

Salu2 a todos...:p:D