Generieren eindeutiger Zufallszahlen in Java

86

Ich versuche, Zufallszahlen zwischen 0 und 100 zu erhalten. Aber ich möchte, dass sie eindeutig sind und nicht in einer Sequenz wiederholt werden. Wenn ich zum Beispiel 5 Zahlen habe, sollten sie 82,12,53,64,32 sein und nicht 82,12,53,12,32. Ich habe dies verwendet, aber es werden die gleichen Zahlen in einer Sequenz generiert.

Random rand = new Random();
selected = rand.nextInt(100);
Ömer Faruk AK
quelle
5
Sie können eine zufällige Permutation des Bereichs erstellen 1..100(dafür gibt es bekannte Algorithmen), aber aufhören, nachdem Sie die ersten nElemente ermittelt haben.
Kerrek SB
Dies könnte nützlich sein Einzigartiger Zufalls-ID-Generator
Erfan Ahmed

Antworten:

141

Hier ist eine einfache Implementierung. Dadurch werden 3 eindeutige Zufallszahlen aus dem Bereich von 1 bis 10 gedruckt.

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(new Integer(i));
        }
        Collections.shuffle(list);
        for (int i=0; i<3; i++) {
            System.out.println(list.get(i));
        }
    }
}

Der erste Teil des Fixes mit dem ursprünglichen Ansatz besteht, wie Mark Byers in einer jetzt gelöschten Antwort hervorhob, darin, nur eine einzige RandomInstanz zu verwenden.

Das führt dazu, dass die Zahlen identisch sind. Eine RandomInstanz wird durch die aktuelle Zeit in Millisekunden gesetzt. Für einen bestimmten Startwert gibt die 'zufällige' Instanz genau dieselbe Folge von Pseudozufallszahlen zurück .

HINWEIS : Der public Integer​(int value)Konstruktor ist deprecatedseit Java 9.

Die erste for-Schleife kann einfach geändert werden in:

for (int i = 1; i < 11; i++) {
  list.add(i);
}
Andrew Thompson
quelle
3
+1 für den Hinweis auf eine einzelne zufällige Instanz und die Beantwortung der Frage. :)
Mark Byers
Sie müssen nicht den gesamten Bereich mischen. Wenn Sie n eindeutige Zahlen möchten, müssen Sie nur die erste n Position mit einem Fisher-Yates-Shuffle mischen. Dies kann bei einer großen Liste und einem kleinen n hilfreich sein.
Rossum
59

Mit Java 8+ können Sie die intsMethode verwenden Random, um IntStreamdann zufällige Werte abzurufen distinctund limitden Stream auf eine Reihe eindeutiger zufälliger Werte zu reduzieren.

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

Randomhat auch Methoden, die LongStreams und erstellenDoubleStream s wenn Sie diese stattdessen benötigen.

Wenn Sie alle (oder eine große Anzahl) Zahlen in einem Bereich in zufälliger Reihenfolge möchten, ist es möglicherweise effizienter, alle Zahlen zu einer Liste hinzuzufügen, sie zu mischen und das erste n zu verwenden, da das obige Beispiel derzeit implementiert ist durch Generieren von Zufallszahlen in dem angeforderten Bereich und Durchlaufen dieser durch einen Satz (ähnlich wie bei Rob Kieltys Antwort ), bei dem möglicherweise viel mehr als der zur Begrenzung übergebene Betrag generiert werden muss, da die Wahrscheinlichkeit, eine neue eindeutige Zahl zu generieren, mit jeder gefundenen Zahl abnimmt. Hier ist ein Beispiel für den anderen Weg:

List<Integer> range = IntStream.range(0, 100).boxed()
        .collect(Collectors.toCollection(ArrayList::new));
Collections.shuffle(range);
range.subList(0, 99).forEach(System.out::println);
Alex - GlassEditor.com
quelle
Ich brauchte dies für einen Code, den ich vergleiche, und Arrays#setAll()ist etwas schneller als ein Stream. Also: `Integer [] Indizes = neue Integer [n]; Arrays.setAll (Indizes, i -> i); Collections.shuffle (Arrays.asList (Indizes)); return Arrays.stream (Indizes) .mapToInt (Integer :: intValue) .toArray (); `
AbuNassar
18
  1. Erstellen Sie ein Array mit 100 Zahlen und ordnen Sie deren Reihenfolge nach dem Zufallsprinzip.
  2. Entwickeln Sie einen Pseudozufallszahlengenerator mit einem Bereich von 100.
  3. Erstellen Sie ein boolesches Array mit 100 Elementen und setzen Sie ein Element auf true, wenn Sie diese Zahl auswählen. Wenn Sie die nächste Nummer auswählen, überprüfen Sie das Array und versuchen Sie es erneut, wenn das Array-Element festgelegt ist. (Sie können ein einfach zu löschendes boolesches Array mit einem Array erstellen, in longdem Sie verschieben und maskieren, um auf einzelne Bits zuzugreifen.)
Hot Licks
quelle
2
+1 für den alternativen Ansatz; pick()ist ein Beispiel.
Trashgod
1
Anstatt ein boolesches Array zu verwenden, können Sie ein verwenden HashSet, in dem Sie die bereits generierten Zahlen speichern und containstesten, ob Sie diese Zahl bereits generiert haben. Das HashSetist wahrscheinlich etwas langsamer als ein boolesches Array, beansprucht aber weniger Speicher.
Rory O'Kane
1
@ RoryO'Kane - Ich bin mir ziemlich sicher, dass das boolesche Array weniger Platz beanspruchen würde, wenn es als Array von long [2] implementiert würde. Auf keinen Fall könnten Sie ein HashSet so klein machen.
Hot Licks
Der letzte Ansatz ist etwas hässlich, da er nicht über eine genau definierte Anzahl von Schritten verfügt, um die gesamte Sequenz zu generieren. Außerdem müssen Sie das Rad nicht neu erfinden - BitSet .
Pavel Horal
16

Verwenden Sie Collections.shuffle()für alle 100 Zahlen und wählen Sie die ersten fünf aus, wie hier gezeigt .

Müllgott
quelle
13

Ich denke, diese Methode ist erwähnenswert.

   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;
    }
Kenny Cason
quelle
9

Ich habe Anands Antwort überarbeitet, um nicht nur die eindeutigen Eigenschaften eines Sets zu nutzen, sondern auch den booleschen Wert false zu verwenden, der von zurückgegeben wird, set.add()wenn ein Hinzufügen zum Set fehlschlägt.

import java.util.HashSet;
import java.util.Random;
import java.util.Set;

public class randomUniqueNumberGenerator {

    public static final int SET_SIZE_REQUIRED = 10;
    public static final int NUMBER_RANGE = 100;

    public static void main(String[] args) {
        Random random = new Random();

        Set set = new HashSet<Integer>(SET_SIZE_REQUIRED);

        while(set.size()< SET_SIZE_REQUIRED) {
            while (set.add(random.nextInt(NUMBER_RANGE)) != true)
                ;
        }
        assert set.size() == SET_SIZE_REQUIRED;
        System.out.println(set);
    }
}
Rob Kielty
quelle
1
Gute Idee. Ein wichtiges Zeichen - wenn SET_SIZE_REQUIREDes groß genug ist (sagen wir, mehr als NUMBER_RANGE / 2dann haben Sie eine viel größere erwartete Laufzeit.
Noamgot
5

Ich habe das so gemacht.

    Random random = new Random();
    ArrayList<Integer> arrayList = new ArrayList<Integer>();

    while (arrayList.size() < 6) { // how many numbers u need - it will 6
        int a = random.nextInt(49)+1; // this will give numbers between 1 and 50.

        if (!arrayList.contains(a)) {
            arrayList.add(a);
        }
    }
Tom
quelle
4

Dies wird funktionieren, um eindeutige Zufallszahlen zu generieren ................

import java.util.HashSet;
import java.util.Random;

public class RandomExample {

    public static void main(String[] args) {
        Random rand = new Random();
        int e;
        int i;
        int g = 10;
        HashSet<Integer> randomNumbers = new HashSet<Integer>();

        for (i = 0; i < g; i++) {
            e = rand.nextInt(20);
            randomNumbers.add(e);
            if (randomNumbers.size() <= 10) {
                if (randomNumbers.size() == 10) {
                    g = 10;
                }
                g++;
                randomNumbers.add(e);
            }
        }
        System.out.println("Ten Unique random numbers from 1 to 20 are  : " + randomNumbers);
    }
}
Anand
quelle
3

Eine clevere Möglichkeit, dies zu tun, besteht darin, Exponenten eines primitiven Elements im Modul zu verwenden.

Zum Beispiel ist 2 ein primitiver Root-Mod 101, was bedeutet, dass die Potenzen von 2 Mod 101 Ihnen eine sich nicht wiederholende Sequenz geben, die jede Zahl von 1 bis einschließlich 100 sieht:

2^0 mod 101 = 1
2^1 mod 101 = 2
2^2 mod 101 = 4
...
2^50 mod 101 = 100
2^51 mod 101 = 99
2^52 mod 101 = 97
...
2^100 mod 101 = 1

In Java-Code würden Sie schreiben:

void randInts() {
int num=1;
for (int ii=0; ii<101; ii++) {
    System.out.println(num);
    num= (num*2) % 101;
    }
}

Es kann schwierig sein, eine primitive Wurzel für einen bestimmten Modul zu finden, aber die "Primroot" -Funktion von Maple erledigt dies für Sie.

AT - Student
quelle
Das ist interessant, aber wie würden wir sicherstellen, dass die generierte Sequenz zufällig ist? Es scheint nicht so zu sein. Es scheint sehr deterministisch zu sein, 1,2,4,8,16, ... am Anfang einer Sequenz zu haben.
h4nek
Es ist nicht zufällig ... es ist pseudozufällig. Niemand weiß, wie man wirklich Zufallszahlen generiert. Wenn Ihnen das ursprüngliche Muster nicht gefällt, können Sie eine größere Basis als primitive Wurzel verwenden.
AT - Student
Pseudozufällig wäre in Ordnung. Aber hier ist für einen gegebenen "Bereich" die Anzahl der primitiven Wurzeln und damit der eindeutigen Sequenzen begrenzt, insbesondere für kleinere Bereiche. Es scheint also ein Problem mit dem Muster zu geben, z. B. immer eine Teilfolge von Potenzen der Wurzel zu haben. Und keine (wahrscheinlich) sehr unterschiedliche Sequenz bei mehreren Läufen zu erhalten, es sei denn, wir wenden weitere Shenanigans an. Ich denke, es hängt vom Anwendungsfall ab. Das Ändern der Basis ist sowieso ein nettes Upgrade, obwohl es nur das Muster "verschiebt".
h4nek
2

Ich bin von einer anderen Frage hierher gekommen, die ein Duplikat dieser Frage war ( Generieren einer eindeutigen Zufallszahl in Java ).

  1. Speichern Sie 1 bis 100 Zahlen in einem Array.

  2. Generieren Sie eine Zufallszahl zwischen 1 und 100 als Position und geben Sie das Array [Position-1] zurück, um den Wert zu erhalten

  3. Wenn Sie eine Zahl im Array verwenden, markieren Sie den Wert als -1 (Sie müssen kein anderes Array pflegen, um zu überprüfen, ob diese Zahl bereits verwendet wird).

  4. Wenn der Wert im Array -1 ist, rufen Sie die Zufallszahl erneut ab, um eine neue Position im Array abzurufen.

Ravindra Babu
quelle
1

Ich habe eine einfache Lösung für dieses Problem. Damit können wir leicht n eindeutige Zufallszahlen generieren. Es ist nur eine Logik, die jeder in jeder Sprache verwenden kann.

for(int i=0;i<4;i++)
        {
            rn[i]= GenerateRandomNumber();
            for (int j=0;j<i;j++)
            {
                if (rn[i] == rn[j])
                {
                    i--;
                }
            }
        }
Devarsh Ranpara
quelle
0

Probieren Sie es aus

public class RandomValueGenerator {
    /**
     * 
     */
    private volatile List<Double> previousGenValues = new ArrayList<Double>();

    public void init() {
        previousGenValues.add(Double.valueOf(0));
    }

    public String getNextValue() {
        Random random = new Random();
        double nextValue=0;
        while(previousGenValues.contains(Double.valueOf(nextValue))) {
            nextValue = random.nextDouble();
        }
        previousGenValues.add(Double.valueOf(nextValue));
        return String.valueOf(nextValue);
    }
}
Rohit Anand
quelle
0

Dies unterscheidet sich nicht wesentlich von anderen Antworten, aber ich wollte am Ende das Array von ganzen Zahlen:

    Integer[] indices = new Integer[n];
    Arrays.setAll(indices, i -> i);
    Collections.shuffle(Arrays.asList(indices));
    return Arrays.stream(indices).mapToInt(Integer::intValue).toArray();
AbuNassar
quelle
0

Sie können ein boolesches Array verwenden, um den Wert true zu füllen, wenn der Wert andernfalls festgelegt ist. Navigieren Sie durch das boolesche Array, um den unten angegebenen Wert zu erhalten

package study;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/*
Created By Sachin  Rane on Jul 18, 2018
*/
public class UniqueRandomNumber {
    static Boolean[] boolArray;
    public static void main(String s[]){
        List<Integer> integers = new ArrayList<>();


        for (int i = 0; i < 10; i++) {
            integers.add(i);
        }


        //get unique random numbers
        boolArray = new Boolean[integers.size()+1];
        Arrays.fill(boolArray, false);
        for (int i = 0; i < 10; i++) {
            System.out.print(getUniqueRandomNumber(integers) + " ");

        }

    }

    private static int  getUniqueRandomNumber(List<Integer> integers) {
        int randNum =(int) (Math.random()*integers.size());
        if(boolArray[randNum]){
            while(boolArray[randNum]){
                randNum++;
                if(randNum>boolArray.length){
                    randNum=0;
                }
            }
            boolArray[randNum]=true;
            return randNum;
        }else {
            boolArray[randNum]=true;
            return randNum;
        }

    }

}
Sachin Rane
quelle
0

Wählen Sie n eindeutige Zufallszahlen von 0 bis m-1.

int[] uniqueRand(int n, int m){
    Random rand = new Random();
    int[] r = new int[n];
    int[] result = new int[n];
    for(int i = 0; i < n; i++){
        r[i] = rand.nextInt(m-i);
        result[i] = r[i];
        for(int j = i-1; j >= 0; j--){
            if(result[i] >= r[j])
                result[i]++;
        }
    }
    return result;
}

Stellen Sie sich eine Liste mit Zahlen von 0 bis m-1 vor. Um die erste Nummer zu wählen, verwenden wir einfach rand.nextInt(m). Entfernen Sie dann die Nummer aus der Liste. Jetzt bleiben m-1 Nummern, also rufen wir anrand.nextInt(m-1) . Die Zahl, die wir erhalten, repräsentiert die Position in der Liste. Wenn es kleiner als die erste Nummer ist, ist es die zweite Nummer, da der Teil der Liste vor der ersten Nummer durch das Entfernen der ersten Nummer nicht geändert wurde. Wenn die Position größer oder gleich der ersten Zahl ist, ist die zweite Zahl Position + 1. Führen Sie eine weitere Ableitung durch, Sie können diesen Algorithmus erhalten.

Erläuterung

Dieser Algorithmus hat eine O (n ^ 2) -Komplexität. Es ist also gut, um aus einer großen Menge eine kleine Menge eindeutiger Zahlen zu generieren. Während der Shuffle-basierte Algorithmus mindestens O (m) benötigt, um das Shuffle durchzuführen.

Auch Shuffle-basierte Algorithmen benötigen Speicher, um jedes mögliche Ergebnis für das Shuffle zu speichern. Dieser Algorithmus benötigt keinen Speicher.

Jeffrey Chen
quelle
0

Sie können die Collections-Klasse verwenden.

Eine Dienstprogrammklasse mit dem Namen "Sammlungen" bietet verschiedene Aktionen, die für eine Sammlung wie eine ArrayList ausgeführt werden können (z. B. Durchsuchen der Elemente, Suchen des maximalen oder minimalen Elements, Umkehren der Reihenfolge der Elemente usw.). Eine der Aktionen, die ausgeführt werden können, besteht darin, die Elemente zu mischen. Durch das Mischen wird jedes Element zufällig an eine andere Position in der Liste verschoben. Dazu wird ein zufälliges Objekt verwendet. Dies bedeutet, dass es deterministische Zufälligkeit ist, aber in den meisten Situationen.

Um die ArrayList zu mischen, fügen Sie den Collections-Import oben im Programm hinzu und verwenden Sie dann die statische Shuffle-Methode. Die ArrayList muss als Parameter gemischt werden:

import java.util.Collections;
import java.util.ArrayList;
public class Lottery {
public static void main(String[] args) {
//define ArrayList to hold Integer objects
ArrayList numbers = new ArrayList();
for(int i = 0; i < 100; i++)
{
numbers.add(i+1);
}
Collections.shuffle(numbers);
System.out.println(numbers);
}
}
Nuwan Harshakumara Piyarathna
quelle
0

Es ist zwar ein alter Thread, aber das Hinzufügen einer weiteren Option kann nicht schaden. (JDK 1.8 Lambda-Funktionen scheinen es einfach zu machen);

Das Problem kann in die folgenden Schritte unterteilt werden:

  • Holen Sie sich einen Mindestwert für die bereitgestellte Liste von Ganzzahlen (für die eindeutige Zufallszahlen generiert werden sollen).
  • Holen Sie sich einen Maximalwert für die angegebene Liste von Ganzzahlen
  • Verwenden Sie die ThreadLocalRandom-Klasse (ab JDK 1.8), um zufällige Ganzzahlwerte für die zuvor gefundenen Min- und Max-Ganzzahlwerte zu generieren, und filtern Sie dann, um sicherzustellen, dass die Werte tatsächlich in der ursprünglich bereitgestellten Liste enthalten sind. Wenden Sie schließlich abschließend auf den Intstream an, um sicherzustellen, dass die generierten Zahlen eindeutig sind.

Hier ist die Funktion mit einer Beschreibung:

/**
 * Provided an unsequenced / sequenced list of integers, the function returns unique random IDs as defined by the parameter
 * @param numberToGenerate
 * @param idList
 * @return List of unique random integer values from the provided list
 */
private List<Integer> getUniqueRandomInts(List<Integer> idList, Integer numberToGenerate) {

    List<Integer> generatedUniqueIds = new ArrayList<>();

    Integer minId = idList.stream().mapToInt (v->v).min().orElseThrow(NoSuchElementException::new);
    Integer maxId = idList.stream().mapToInt (v->v).max().orElseThrow(NoSuchElementException::new);

            ThreadLocalRandom.current().ints(minId,maxId)
            .filter(e->idList.contains(e))
            .distinct()
            .limit(numberToGenerate)
            .forEach(generatedUniqueIds:: add);

    return generatedUniqueIds;

}

Um 11 eindeutige Zufallszahlen für das Listenobjekt 'allIntegers' zu erhalten, rufen wir die Funktion wie folgt auf:

    List<Integer> ids = getUniqueRandomInts(allIntegers,11);

Die Funktion deklariert die neue ArrayList 'generateUniqueIds' und füllt sie mit jeder eindeutigen zufälligen Ganzzahl bis zur erforderlichen Anzahl, bevor sie zurückkehrt.

Die PS ThreadLocalRandom-Klasse vermeidet bei gleichzeitigen Threads den allgemeinen Startwert.

Kamran Hyder
quelle
0

Dies ist die einfachste Methode, um eindeutige Zufallswerte in einem Bereich oder aus einem Array zu generieren .

In diesem Beispiel verwende ich ein vordefiniertes Array, aber Sie können diese Methode auch anpassen, um Zufallszahlen zu generieren. Zuerst erstellen wir ein Beispielarray, aus dem wir unsere Daten abrufen können.

  1. Generieren Sie eine Zufallszahl und fügen Sie sie dem neuen Array hinzu.
  2. Generieren Sie eine weitere Zufallszahl und prüfen Sie, ob diese bereits im neuen Array gespeichert ist.
  3. Wenn nicht, fügen Sie es hinzu und fahren Sie fort
  4. Andernfalls wiederholen Sie den Schritt.
ArrayList<Integer> sampleList = new ArrayList<>();
sampleList.add(1);
sampleList.add(2);
sampleList.add(3);
sampleList.add(4);
sampleList.add(5);
sampleList.add(6);
sampleList.add(7);
sampleList.add(8);

Aus dem werden sampleListwir nun fünf Zufallszahlen erzeugen, die eindeutig sind.

int n;
randomList = new ArrayList<>();
for(int  i=0;i<5;i++){
    Random random = new Random();
    n=random.nextInt(8);     //Generate a random index between 0-7

    if(!randomList.contains(sampleList.get(n)))
    randomList.add(sampleList.get(n));
    else
        i--;    //reiterating the step
}
        

Dies ist konzeptionell sehr einfach. Wenn der generierte Zufallswert bereits vorhanden ist, wiederholen wir den Schritt. Dies wird fortgesetzt, bis alle generierten Werte eindeutig sind.

Wenn Sie diese Antwort nützlich fanden, können Sie sie abstimmen, da das Konzept im Vergleich zu den anderen Antworten sehr einfach ist .

Partha Prateem Patra
quelle
-1

Sie können in Java n eindeutige Zufallszahlen zwischen 0 und n-1 generieren

public static void RandomGenerate(int n)
{
     Set<Integer> st=new HashSet<Integer>();
     Random r=new Random();
     while(st.size()<n)
     {
        st.add(r.nextInt(n));
     }

}}

Baliram Gupta
quelle
-2

Überprüfen Sie dies

public class RandomNumbers {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        int n = 5;
        int A[] = uniqueRandomArray(n);
        for(int i = 0; i<n; i++){
            System.out.println(A[i]);
        }
    }
    public static int[] uniqueRandomArray(int n){
        int [] A = new int[n];
        for(int i = 0; i< A.length; ){
            if(i == A.length){
                break;
            }
            int b = (int)(Math.random() *n) + 1;
            if(f(A,b) == false){
                A[i++] = b;
            } 
        }
        return A;
    }
    public static boolean f(int[] A, int n){
        for(int i=0; i<A.length; i++){
            if(A[i] == n){
                return true;
            }
        }
        return false;
    }
}
Artashes Khachatryan
quelle
2
Java-Standards, Lesbarkeit und Benutzerfreundlichkeit aus dem Fenster werfen, oder?
Austin Wernli
Code ist keine Antwort. Sie schreiben eine Antwort und fügen dann Code hinzu, um zu erklären, was Sie wollten.
Aditya
-2

Im Folgenden finden Sie eine Methode, mit der ich immer eine eindeutige Nummer generiert habe. Die Zufallsfunktion generiert eine Nummer und speichert sie in einer Textdatei. Beim nächsten Einchecken in eine Datei wird sie verglichen und eine neue eindeutige Nummer generiert. Auf diese Weise gibt es immer eine neue eindeutige Nummer.

public int GenerateRandomNo()
{
    int _min = 0000;
    int _max = 9999;
    Random _rdm = new Random();
    return _rdm.Next(_min, _max);
}
public int rand_num()
{
    randnum = GenerateRandomNo();
    string createText = randnum.ToString() + Environment.NewLine;
    string file_path = System.IO.Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath) + @"\Invoices\numbers.txt";
    File.AppendAllText(file_path, createText);
    int number = File.ReadLines(file_path).Count(); //count number of lines in file
    System.IO.StreamReader file = new System.IO.StreamReader(file_path);
    do
    {
        randnum = GenerateRandomNo();
    }
    while ((file.ReadLine()) == randnum.ToString());
    file.Close();
    return randnum;

}
NightOwl888
quelle