Como escolher um numero randomicamente!

Pessoal,

Atenção, já vou deixar claro que não quero gerar um Random ok?

O problema é o seguinte:

Digamos que eu tenha 4 números (2,5,7,9)

Eu apenas quero escolher um desses números randomicamente.

Eu pensei em fazer um random entre 1 e 10, se o numero gerado nao for algum desses 4, eu gero o rand novamente, porém existe a possibilidade de eu ficar no loop por muito tempo…

Alguém tem alguma sugestão?

Obrigado!

crie um array com os numeros, depois use o random() para escolher o indice.

[code]//Crie uma lista com os números
List<Integer> numeros = new ArrayList<Integer>();
numeros.add(2);
numeros.add(5);
numeros.add(7);
numeros.add(9);

//Embaralhe a lista
Collections.shuffle(numeros);

//Agora é só pegar os números
System.out.println(numeros.get(0));[/code]

A vantagem do método acima é que você pode eliminar o número de índice 0 da lista. E assim, o próximo zero não se repetirá. Bem prático caso você queira fazer um programa de sorteio da mega-sena.

Uma variação é a utilização da classe java.util.Random para sortear os elementos da lista, como no exemplo abaixo.

List<Integer> numeros = new ArrayList<Integer>();  
numeros.add(2);  
numeros.add(5);  
numeros.add(7);  
numeros.add(9);  

System.out.println(numeros.get(new Random().nextInt(numeros.size())));

O método nextInt(int n) da classe Random sorteia um número inteiro entre 0 e (n - 1). No exemplo acima, o método sorteará um número entre 0 e o tamanho da lista - 1 (4 - 1).

Simplesmente perfeito! Obrigado a todos.

O ideal é não fazer new Random() inline, como você fez. Isso não garante a geração de números aleatórios caso o método seja chamado várias vezes seguidas, num for, por exemplo. Faça você mesmo o teste:

[code]public void gerarNumero() {
List numeros = new ArrayList();
numeros.add(2);
numeros.add(5);
numeros.add(7);
numeros.add(9);

System.out.println(numeros.get(new Random().nextInt(numeros.size())));
}

public static void main(String[] args) {
for (int i = 0; i < 100; i++)
gerarNumero();
}
[/code]

Para corrigir, retira-se o Random para fora do método, e só inicializa ele uma única vez:

public static final Random RANDOM = new Random();

public void gerarNumero() {
   List<Integer> numeros = new ArrayList<Integer>();    
   numeros.add(2);    
   numeros.add(5);    
   numeros.add(7);    
   numeros.add(9);    

   System.out.println(numeros.get(RANDOM.nextInt(numeros.size())));  
}

ViniGodoy, o que você disse é valido… Neste mesmo projeto porém em outro problema, eu tive que gerar random dentro de um loop!

Só que tive que por um sleep de 25 milisegundos, senão acabava gerando numeros iguais de vez enquando.

Complicado né, fazer oq, ficou bem mais lento, mas a chance do numero nao repetir é maior!

Abraço

Se você criar o objeto random fora do loop, o número não se repetirá.

E gerar números iguais de vez enquando é normal. Afinal, o número é aleatório! O que não pode é gerar vários deles seguidos.

O ideal é não fazer new Random() inline, como você fez. Isso não garante a geração de números aleatórios caso o método seja chamado várias vezes seguidas, num for, por exemplo. Faça você mesmo o teste:
(…)
[/code]

Para corrigir, retira-se o Random para fora do método, e só inicializa ele uma única vez:

(...) [/quote]

Até por questão de evitar a criação de vários objetos desnecessariamnete, sua sugestão é válida. Sempre utilizo essa abordagem.
Quanto a várias instâncias gerarem os números aleatórios, você sabe se por exemplo, em duas chamadas consecutivas, é possível que o seed do Random seja o mesmo currentTimeMillis?

[quote=felipealbuquerque]Até por questão de evitar a criação de vários objetos desnecessariamnete, sua sugestão é válida. Sempre utilizo essa abordagem.
Quanto a várias instâncias gerarem os números aleatórios, você sabe se por exemplo, em duas chamadas consecutivas, é possível que o seed do Random seja o mesmo currentTimeMillis?[/quote]

Se as camadas forem criadas simultaneamente, sim. Mas isso geralmente é difícil de acontecer. Se não quiser contar com isso, você pode definir na mão um offset para cada random:

public void Random random = new Random(System.currentTimeMillis() + offset);

Onde offset é um número qualquer como -1, 1, 2, 3, diferente para cada camada.

Normalmente eu prefiro ter um único gerador Random, e definido estaticamente ainda por cima. Ou seja:

import java.security.SecureRandom;
...
private static Random r = new SecureRandom();
...

Isso não dá problemas relacionados a ficar criando instâncias de Random que são inicializadas com o mesmo valor de semente (que no caso é System.currentTimeMillis(), um valor que no Windows tem precisão de apenas 10 milissegundos ou ainda mais inexato.)

Entretanto, em alguns sistemas operacionais, SecureRandom “prende” um pouco a execução de seu programa. Por exemplo, em um Linux ele é implementado em termos de /dev/rand ou /dev/random (não tenho certeza), e esse “device” é um bocadinho lento ao ser inicializado. No Windows, é implementado em termos de CryptGenerateRandom (não lembro mais o nome da API), e essa implementação depende do provider da CryptoAPI - às vezes é gerado por hardware, se algum driver de algum dispositivo criptográfico estiver instalado. Aí ele também pode “prender” um pouco a execução.