98 votes

Génération de nombres aléatoires uniques en Java

J'essaie d'obtenir des nombres aléatoires compris entre 0 et 100. Mais je veux qu'ils soient uniques, et non répétés dans une séquence. Par exemple, si j'obtiens 5 numéros, ils doivent être 82,12,53,64,32 et non 82,12,53,12,32. J'ai utilisé ceci, mais cela génère les mêmes nombres dans une séquence.

Random rand = new Random();
selected = rand.nextInt(100);

5 votes

Vous pourriez créer un permutation aléatoire de la gamme 1..100 (il existe des algorithmes célèbres pour cela), mais arrêtez-vous après avoir déterminé le premier n éléments.

0 votes

0 votes

157voto

Andrew Thompson Points 108505
  • Additionnez chaque nombre de la plage de manière séquentielle dans un tableau. liste structure.
  • Shuffle il.
  • Prenez le premier "n".

Voici une mise en œuvre simple. Elle imprimera 3 nombres aléatoires uniques compris entre 1 et 10.

import java.util.ArrayList;
import java.util.Collections;

public class UniqueRandomNumbers {

    public static void main(String[] args) {
        ArrayList<Integer> list = new ArrayList<Integer>();
        for (int i=1; i<11; i++) {
            list.add(i);
        }
        Collections.shuffle(list);
        for (int i=0; i<3; i++) {
            System.out.println(list.get(i));
        }
    }
}

La première partie de la correction de l'approche originale, comme Mark Byers l'a fait remarquer dans une réponse maintenant supprimée, consiste à n'utiliser qu'une seule et unique Random instance.

C'est ce qui fait que les chiffres sont identiques. A Random est alimentée par le temps actuel en millisecondes. Pour une valeur de la graine, l'instance 'aléatoire' renverra exactement la même séquence de pseudo-aléatoire numéros.

65voto

Alex Points 1092

Avec Java 8+, vous pouvez utiliser la fonction ints méthode de Random pour obtenir un IntStream de valeurs aléatoires, alors distinct y limit pour réduire le flux à un certain nombre de valeurs aléatoires uniques.

ThreadLocalRandom.current().ints(0, 100).distinct().limit(5).forEach(System.out::println);

Random a également des méthodes qui créent LongStream et DoubleStream si vous en avez besoin.

Si vous voulez tous (ou une grande quantité de nombres dans une plage dans un ordre aléatoire, il peut être plus efficace d'ajouter tous les nombres à une liste, de la mélanger, et de prendre les n premiers car l'exemple ci-dessus est actuellement mis en œuvre en générant des nombres aléatoires dans la plage demandée et en les passant par un ensemble (de manière similaire à La réponse de Rob Kielty ), ce qui peut nécessiter d'en générer beaucoup plus que la quantité passée à la limite car la probabilité de générer un nouveau numéro unique diminue avec chaque numéro trouvé. Voici un exemple de l'autre façon de procéder :

List<Integer> range = IntStream.range(0, 100).boxed()
        .collect(Collectors.toCollection(ArrayList::new));
Collections.shuffle(range);
range.subList(0, 99).forEach(System.out::println);

18voto

Hot Licks Points 25075
  1. Créez un tableau de 100 nombres, puis rendez leur ordre aléatoire.
  2. Concevez un générateur de nombres pseudo-aléatoires dont la plage est de 100.
  3. Créez un tableau booléen de 100 éléments, puis mettez un élément à true lorsque vous choisissez ce nombre. Lorsque vous choisissez le nombre suivant, vérifiez le tableau et réessayez si l'élément du tableau est activé. (Vous pouvez créer un tableau booléen facile à comprendre avec un tableau de long où l'on décale et masque pour accéder aux bits individuels).

2 votes

+1 pour l'approche alternative ; pick() est un exemple.

1 votes

Au lieu d'utiliser un tableau de booléens, vous pouvez utiliser un tableau de type HashSet où vous stockez les numéros que vous avez déjà générés et utilisés. contains pour vérifier si vous avez déjà généré ce numéro. Le site HashSet sera probablement légèrement plus lent qu'un tableau de booléens, mais occupera moins de mémoire.

1 votes

@RoryO'Kane -- Je suis presque sûr que le tableau de booléens prendrait moins de place, s'il était implémenté comme un tableau de long[2]. Il est impossible de faire un HashSet aussi petit.

16voto

trashgod Points 136305

Utilice Collections.shuffle() sur l'ensemble des 100 numéros et sélectionner les cinq premiers, comme indiqué aquí .

15voto

Kenny Cason Points 3523

Je pense que cette méthode mérite d'être mentionnée.

   private static final Random RANDOM = new Random();    
   /**
     * Pick n numbers between 0 (inclusive) and k (inclusive)
     * While there are very deterministic ways to do this,
     * for large k and small n, this could be easier than creating
     * an large array and sorting, i.e. k = 10,000
     */
    public Set<Integer> pickRandom(int n, int k) {
        final Set<Integer> picked = new HashSet<>();
        while (picked.size() < n) {
            picked.add(RANDOM.nextInt(k + 1));
        }
        return picked;
    }

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X