Java'da Benzersiz Rastgele Sayılar Oluşturma


90

0 ile 100 arasında rastgele sayılar elde etmeye çalışıyorum. Ancak bunların benzersiz olmasını, bir sırayla tekrarlanmamasını istiyorum. Örneğin 5 numara aldıysam, 82,12,53,64,32 olmalı ve 82,12,53,12,32 değil bunu kullandım, ancak bir dizide aynı sayıları üretiyor.

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

5
Aralığın rastgele bir permütasyonunu oluşturabilirsiniz 1..100(bunun için ünlü algoritmalar vardır), ancak ilk nöğeleri belirledikten sonra durabilirsiniz .
Kerrek SB



Yanıtlar:


146
  • Aralıktaki her sayıyı bir liste yapısında sırayla ekleyin .
  • Karıştırın .
  • İlk 'n'yi alın.

İşte basit bir uygulama. Bu, 1-10 aralığından 3 benzersiz rastgele sayı yazdıracaktır.

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));
        }
    }
}

Mark Byers'ın artık silinmiş bir yanıtta belirttiği gibi, orijinal yaklaşımla düzeltmenin ilk kısmı, yalnızca tek bir Randomörnek kullanmaktır.

Sayıların aynı olmasına neden olan budur. Bir Randomörnek, milisaniye cinsinden geçerli saate göre tohumlanır. Belirli bir çekirdek değeri için, 'rastgele' örnek tam olarak aynı sözde rastgele sayı dizisini döndürecektir .

NOT o public Integer​(int value)yapıcısı olan deprecatedJava 9 beri.

İlk for döngüsü basitçe şu şekilde değiştirilebilir:

for (int i = 1; i < 11; i++) {
  list.add(i);
}

3
Tek rastgele örneği işaret etmek ve soruyu cevaplamak için +1 :)
Mark Byers

Tüm aralığı karıştırmanız gerekmez. Eğer n benzersiz sayı istiyorsanız, o zaman ilk n konumu bir Fisher-Yates karıştırması kullanarak karıştırmanız yeterlidir. Bu, büyük bir liste ve küçük bir n.
rossum

62

Java 8+ ile rasgele değerler elde etme ve akışı bir dizi benzersiz rasgele değere düşürme intsyöntemini kullanabilirsiniz .RandomIntStreamdistinctlimit

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

RandomBunun yerine bunlara ihtiyacınız varsa LongStreams ve DoubleStreams oluşturan yöntemleri de vardır .

Bir aralıktaki sayıların tümünü (veya büyük bir miktarını) rastgele bir sırayla istiyorsanız, tüm sayıları bir listeye eklemek, karıştırmak ve ilk n'yi almak daha verimli olabilir çünkü yukarıdaki örnek şu anda uygulanmaktadır. İstenen aralıkta rastgele sayılar oluşturarak ve bunları bir kümeden geçirerek ( Rob Kielty'nin cevabına benzer şekilde ), bu, sınıra aktarılan miktardan çok daha fazlasını üretmeyi gerektirebilir çünkü yeni benzersiz bir sayı üretme olasılığı bulunan her biri ile azalır. İşte diğer yolun bir örneği:

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

Buna, karşılaştırdığım bazı kodlar için ihtiyacım vardı ve Arrays#setAll()bir akıştan biraz daha hızlı. Yani: `Tamsayı [] indisler = yeni Tamsayı [n]; Arrays.setAll (indisler, i -> i); Collections.shuffle (Arrays.asList (indisler)); return Arrays.stream (indisler) .mapToInt (Integer :: intValue) .toArray (); `
AbuNassar

18
  1. 100 sayılık bir dizi oluşturun, ardından sıralarını rastgele sıralayın.
  2. 100 aralığa sahip sözde rastgele bir sayı üreteci tasarlayın.
  3. 100 öğeden oluşan bir boole dizisi oluşturun, ardından bu sayıyı seçtiğinizde bir true öğesi ayarlayın. Bir sonraki sayıyı seçtiğinizde, diziyi kontrol edin ve dizi elemanı ayarlanmışsa tekrar deneyin. (Tek longtek bitlere erişmek için kaydırdığınız ve maskelediğiniz bir dizi ile temizlemesi kolay bir boolean dizisi yapabilirsiniz .)

2
Alternatif yaklaşım için +1; pick()bir örnektir.
trashgod

1
Bir boole dizisi kullanmak yerine, HashSetdaha önce oluşturduğunuz sayıları sakladığınız ve bu sayıyı zaten oluşturup oluşturmadığınızı containstest etmek için kullandığınız a kullanabilirsiniz . Bu HashSet, muhtemelen bir boole dizisinden biraz daha yavaş olacaktır, ancak daha az bellek kaplar.
Rory O'Kane

1
@ RoryO'Kane - Uzun [2] dizisi olarak uygulanırsa boole dizisinin daha az yer kaplayacağından eminim. Bir HashSet'i bu kadar küçük yapmanın hiçbir yolu yok.
Hot Licks

Son yaklaşım, tüm diziyi oluşturmak için iyi tanımlanmış adım sayısına sahip olmayacağından biraz çirkin. Ayrıca tekerleği yeniden icat etmenize gerek yok - BitSet .
Pavel Horal


13

Bu yöntemin bahsetmeye değer olduğunu düşünüyorum.

   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;
    }

9

Anand'ın yanıtını yalnızca bir Kümenin benzersiz özelliklerinden yararlanmakla kalmayıp, aynı zamanda set.add()kümeye bir ekleme başarısız olduğunda döndürülen boolean false değerini de kullanmak için yeniden faktörlendirdim .

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);
    }
}

1
İyi fikir. Yine de önemli bir işaret - SET_SIZE_REQUIREDyeterince büyükse (diyelim, NUMBER_RANGE / 2o zamandan daha fazla, beklenen çalışma süresinin çok daha fazla olduğunu
varsayalım

5

Ben bunu böyle yaptım.

    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);
        }
    }

4

Bu, benzersiz rastgele sayılar üretmek için çalışacaktır ................

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);
    }
}

3

Bunu yapmanın akıllıca bir yolu, modüldeki ilkel bir elemanın üslerini kullanmaktır.

Örneğin, 2 ilkel bir kök mod 101'dir, yani 2 mod 101'in kuvvetleri size 1'den 100'e kadar her sayıyı gören tekrar etmeyen bir dizi verir:

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

Java kodunda şöyle yazarsınız:

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

Belirli bir modül için ilkel bir kök bulmak zor olabilir, ancak Maple'ın "ilk kök" işlevi bunu sizin için yapacaktır.


Bu ilginç, ancak üretilen sıranın rastgele olmasını nasıl sağlayabiliriz? Öyle görünmüyor. Bir dizinin başlangıcında 1,2,4,8,16 ... olması çok deterministik görünüyor.
h4nek

Rastgele değil ... sözde rastgele. Gerçekten rastgele sayıların nasıl üretileceğini kimse bilmiyor. İlk kalıbı beğenmezseniz, ilkel kök olarak daha büyük bir taban kullanabilirsiniz.
AT - öğrenci

Sözde rasgele iyi olur. Ancak burada, belirli bir "aralık" için, ilkel köklerin miktarı ve dolayısıyla benzersiz diziler, özellikle daha küçük aralıklar için sınırlıdır. Dolayısıyla, örüntüde bir sorun var gibi görünüyor, örneğin, her zaman kökün bir güç alt dizisine sahip olmak. Ve daha fazla saçmalık uygulamadığımız sürece, birden fazla çalışmada (muhtemelen) çok farklı bir sekans elde edemeyeceğiz. Sanırım kullanım durumuna bağlı. Tabanı değiştirmek yine de güzel bir yükseltmedir, ancak bu sadece kalıbı "değiştirir".
h4nek

2

Buraya, bu sorunun kopyası olan başka bir sorudan geldim ( java'da benzersiz rastgele sayı oluşturma )

  1. Bir Dizide 1 ila 100 numara saklayın.

  2. Konum olarak 1 ile 100 arasında rastgele sayı üretin ve değeri almak için [konum-1] dizisini döndürün

  3. Dizide bir sayı kullandığınızda, değeri -1 olarak işaretleyin (Bu sayının halihazırda kullanılıp kullanılmadığını kontrol etmek için başka bir diziye gerek yoktur)

  4. Dizideki değer -1 ise, dizideki yeni konumu getirmek için rasgele sayıyı tekrar alın.


2

Bu problem için kolay bir çözümüm var, Bununla kolayca n sayıda benzersiz rastgele sayı üretebiliriz, Bu sadece mantığı herhangi bir dilde kullanabilir.

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

Bir yaparak optimize edebilirsiniz break;sonrasıi—;
Jan

1

Eski bir konu olmasına rağmen, başka bir seçenek eklemek zarar vermeyebilir. (JDK 1.8 lambda işlevleri bunu kolaylaştırıyor gibi görünüyor);

Sorun aşağıdaki adımlara bölünebilir;

  • Sağlanan tamsayı listesi için minimum bir değer alın (bunun için benzersiz rastgele sayılar üretilir)
  • Sağlanan tamsayı listesi için bir maksimum değer alın
  • Önceden bulunan minimum ve maksimum tam sayı değerlerine karşı rastgele tamsayı değerleri oluşturmak için ThreadLocalRandom sınıfını (JDK 1.8'den) kullanın ve ardından değerlerin orijinal olarak sağlanan liste tarafından gerçekten içerildiğinden emin olmak için filtre uygulayın. Son olarak, üretilen sayıların benzersiz olduğundan emin olmak için intstream'e farklı uygulayın.

İşte bazı açıklamaları olan işlev:

/**
 * 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;

}

Böylece, 'allIntegers' liste nesnesi için 11 benzersiz rasgele sayı elde etmek için, aşağıdaki gibi işlevi çağıracağız;

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

İşlev, yeni arrayList 'createdUniqueIds' bildirir ve dönmeden önce gereken sayıya kadar her benzersiz rasgele tamsayı ile doldurur.

PS ThreadLocalRandom sınıfı, eşzamanlı iş parçacıkları olması durumunda ortak çekirdek değerinden kaçınır.


0

bunu dene

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);
    }
}

0

Bu, diğer yanıtlardan önemli ölçüde farklı değil, ancak sonunda tamsayı dizisini istedim:

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

0

Boolean dizisini, eğer alınan değer doğruysa doldurmak için kullanabilirsiniz, aksi takdirde, aşağıda verilen değeri elde etmek için boole dizisinde gezinin

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;
        }

    }

}

0

0 ile m-1 arasında n benzersiz rastgele sayı seçin.

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;
}

0'dan m-1'e kadar sayılar içeren bir liste hayal edin. İlk sayıyı seçmek için kullanıyoruz rand.nextInt(m). Ardından numarayı listeden kaldırın. Şimdi m-1 numaraları kaldı, bu yüzden arıyoruzrand.nextInt(m-1) . Aldığımız sayı, listedeki konumu temsil eder. İlk sayıdan küçükse, ikinci sayıdır, çünkü listenin ilk sayıdan önceki kısmı, birinci sayı kaldırılarak değiştirilmemiştir. Konum ilk sayıdan büyük veya ona eşitse, ikinci sayı konum + 1'dir. Biraz daha türetme yapın, bu algoritmayı elde edebilirsiniz.

Açıklama

Bu algoritma O (n ^ 2) karmaşıklığına sahiptir. Bu nedenle, büyük bir kümeden az miktarda benzersiz sayılar üretmek için iyidir. Karıştırma tabanlı algoritmanın karıştırmayı yapmak için en az O (m) değerine ihtiyacı vardır.

Ayrıca karıştırma tabanlı algoritma, karıştırmayı gerçekleştirmek için olası her sonucu depolamak için belleğe ihtiyaç duyar, bu algoritmanın ihtiyacı yoktur.


0

Koleksiyonlar sınıfını kullanabilirsiniz.

Koleksiyonlar adı verilen bir yardımcı sınıf, bir ArrayList gibi bir koleksiyonda gerçekleştirilebilecek farklı eylemler sunar (örneğin, öğeleri arayın, maksimum veya minimum öğeyi bulun, öğelerin sırasını tersine çevirin vb.). Gerçekleştirebileceği eylemlerden biri, öğeleri karıştırmaktır. Karıştırma, her bir öğeyi listede rastgele farklı bir konuma taşıyacaktır. Bunu bir Random nesnesi kullanarak yapar. Bu deterministik rastgelelik olduğu anlamına gelir, ancak çoğu durumda işe yarar.

ArrayList'i karıştırmak için, Koleksiyonlar içe aktarımını programın üstüne ekleyin ve ardından Shuffle statik yöntemini kullanın. ArrayList'in parametre olarak karıştırılması gerekir:

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);
}
}

-1

Java'da 0 ile n-1 arasında n benzersiz rastgele sayı üretebilirsiniz

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));
     }

}


-1

Bu, bir aralıkta veya bir diziden benzersiz rastgele değerler oluşturmanın en basit yöntemidir .

Bu örnekte, önceden tanımlanmış bir dizi kullanacağım, ancak bu yöntemi rastgele sayılar oluşturmak için de uyarlayabilirsiniz. İlk olarak, verilerimizi almak için örnek bir dizi oluşturacağız.

  1. Rastgele bir sayı oluşturun ve yeni diziye ekleyin.
  2. Başka bir rasgele sayı oluşturun ve yeni dizide zaten depolanmış olup olmadığını kontrol edin.
  3. Değilse ekleyin ve devam edin
  4. aksi takdirde adımı tekrarlayın.
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);

Şimdi sampleList, benzersiz olan beş rastgele sayı üreteceğiz.

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
}
        

Bu kavramsal olarak çok basit. Oluşturulan rastgele değer zaten mevcutsa, adımı tekrarlayacağız. Bu, üretilen tüm değerler benzersiz olana kadar devam edecektir.

Bu cevabı faydalı bulduysanız, diğer cevaplara kıyasla konsept olarak çok basit olduğu için oylayabilirsiniz .


-2

Şuna göz at

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;
    }
}

2
Java standartlarını, okunabilirliği ve kullanılabilirliği pencereden dışarı atmak ha?
austin wernli

Kod bir cevap değildir .. Bir cevap yazarsınız ve sonra ne istediğinizi açıklamak için kod eklersiniz.
Aditya

-2

Aşağıda, her zaman benzersiz sayı oluşturmak için kullandığım bir yöntem var. Rastgele işlevi sayı üretir ve metin dosyasında saklar, daha sonra bir dahaki sefere dosyada kontrol eder ve onu karşılaştırır ve yeni benzersiz sayı üretir, dolayısıyla bu şekilde her zaman yeni benzersiz bir sayı vardır.

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;

}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.