Tạo số ngẫu nhiên duy nhất trong Java


87

Tôi đang cố gắng lấy các số ngẫu nhiên từ 0 đến 100. Nhưng tôi muốn chúng là duy nhất, không lặp lại trong một chuỗi. Ví dụ: nếu tôi có 5 số, chúng phải là 82,12,53,64,32 chứ không phải 82,12,53,12,32 Tôi đã sử dụng số này, nhưng nó tạo ra các số giống nhau trong một chuỗi.

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

5
Bạn có thể tạo một hoán vị ngẫu nhiên của phạm vi 1..100(có các thuật toán nổi tiếng cho điều đó), nhưng dừng lại sau khi bạn xác định các nphần tử đầu tiên .
Kerrek SB



Điều này có thể hữu ích phát Id ngẫu nhiên độc đáo
Erfan Ahmed

Câu trả lời:


143
  • Thêm tuần tự từng số trong phạm vi theo cấu trúc danh sách .
  • Xáo trộn nó.
  • Lấy chữ 'n' đầu tiên.

Đây là một cách thực hiện đơn giản. Thao tác này sẽ in ra 3 số ngẫu nhiên duy nhất từ ​​phạm vi 1-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(new Integer(i));
        }
        Collections.shuffle(list);
        for (int i=0; i<3; i++) {
            System.out.println(list.get(i));
        }
    }
}

Phần đầu tiên của bản sửa lỗi với cách tiếp cận ban đầu, như Mark Byers đã chỉ ra trong một câu trả lời hiện đã bị xóa, là chỉ sử dụng một Randomtrường hợp duy nhất .

Đó là những gì đang gây ra các con số giống hệt nhau. Một Randomphiên bản được khởi tạo theo thời gian hiện tại tính bằng mili giây. Đối với một giá trị gốc cụ thể , trường hợp 'ngẫu nhiên' sẽ trả về cùng một chuỗi các số ngẫu nhiên giả giống hệt nhau .

LƯU Ý rằng hàm public Integer​(int value)tạo là deprecatedtừ Java 9.

Vòng lặp for đầu tiên chỉ có thể được thay đổi thành:

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

3
+1 để chỉ ra trường hợp ngẫu nhiên duy nhất trả lời câu hỏi. :)
Mark Byers

Bạn không cần phải xáo trộn toàn bộ phạm vi. Nếu bạn muốn có n số duy nhất, thì bạn chỉ cần xáo trộn n vị trí đầu tiên bằng cách sử dụng xáo trộn Fisher-Yates. Điều này có thể hữu ích với một danh sách lớn và một n nhỏ.
rossum

59

Với Java 8+, bạn có thể sử dụng intsphương pháp Randomđể nhận một IntStreamtrong các giá trị ngẫu nhiên sau đó distinctlimitgiảm luồng xuống một số giá trị ngẫu nhiên duy nhất.

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

Randomcũng có các phương thức tạo LongStreams và DoubleStreams nếu bạn cần chúng thay thế.

Nếu bạn muốn tất cả (hoặc một lượng lớn) các số trong một phạm vi theo thứ tự ngẫu nhiên thì có thể hiệu quả hơn nếu thêm tất cả các số vào danh sách, xáo trộn nó và lấy n đầu tiên vì ví dụ trên hiện đang được triển khai bằng cách tạo các số ngẫu nhiên trong phạm vi được yêu cầu và chuyển chúng qua một tập hợp (tương tự như câu trả lời của Rob Kielty ), điều này có thể yêu cầu tạo nhiều hơn số lượng đã vượt qua giới hạn vì xác suất tạo ra một số duy nhất mới giảm với mỗi số được tìm thấy. Đây là một ví dụ về cách khác:

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

Tôi cần cái này cho một số mã mà tôi đang đo điểm chuẩn và Arrays#setAll()nhanh hơn một chút so với luồng. Vì vậy: `Integer [] indices = new Integer [n]; Arrays.setAll (chỉ số, i -> i); Collections.shuffle (Arrays.asList (các chỉ số)); trả về Arrays.stream (các chỉ số) .mapToInt (Integer :: intValue) .toArray (); `
AbuNassar

18
  1. Tạo một mảng gồm 100 số, sau đó sắp xếp thứ tự ngẫu nhiên của chúng.
  2. Phát triển trình tạo số giả ngẫu nhiên có phạm vi 100.
  3. Tạo một mảng boolean gồm 100 phần tử, sau đó đặt một phần tử là true khi bạn chọn số đó. Khi bạn chọn số tiếp theo, hãy kiểm tra mảng và thử lại xem phần tử mảng đã được đặt chưa. (Bạn có thể tạo một mảng boolean dễ xóa với một mảng longnơi bạn dịch chuyển và mặt nạ để truy cập các bit riêng lẻ.)

2
+1 cho cách tiếp cận thay thế; pick()là một ví dụ.
trashgod

1
Thay vì sử dụng mảng boolean, bạn có thể sử dụng a HashSet, nơi bạn lưu trữ các số bạn đã tạo và sử dụng containsđể kiểm tra xem bạn đã tạo số đó chưa. Có HashSetthể sẽ chậm hơn một chút so với mảng boolean, nhưng chiếm ít bộ nhớ hơn.
Rory O'Kane

1
@ RoryO'Kane - Tôi khá chắc chắn rằng mảng boolean sẽ chiếm ít không gian hơn, nếu được triển khai dưới dạng một mảng dài [2]. Không có cách nào để bạn có thể tạo một HashSet nhỏ như vậy.
Hot Licks vào

Cách tiếp cận cuối cùng hơi xấu xí vì nó sẽ không có một số bước được xác định rõ ràng để tạo toàn bộ chuỗi. Ngoài ra, bạn không cần phải phát minh lại bánh xe - BitSet .
Pavel Horal

16

Sử dụng Collections.shuffle()trên tất cả 100 số và chọn năm số đầu tiên, như được hiển thị ở đây .


13

Tôi cảm thấy như phương pháp này là đáng nói.

   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

Tôi đã kiểm chứng lại câu trả lời của Anand để sử dụng không chỉ các thuộc tính duy nhất của một Tập hợp mà còn sử dụng sai boolean được trả về set.add()khi một bổ sung vào tập hợp không thành công.

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
Ý kiến ​​hay. Tuy nhiên, một dấu ấn quan trọng - nếu SET_SIZE_REQUIREDđủ lớn (giả sử, hơn thế nữa, NUMBER_RANGE / 2bạn đã có thời gian chạy dự kiến ​​lớn hơn nhiều.
noamgot 9/118

5

Tôi đã làm điều này như thế này.

    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

Điều này sẽ hoạt động để tạo ra các số ngẫu nhiên duy nhất ................

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

Một cách thông minh để làm điều này là sử dụng số mũ của một phần tử nguyên thủy trong môđun.

Ví dụ: 2 là một mod gốc nguyên thủy 101, nghĩa là lũy thừa của 2 mod 101 cung cấp cho bạn một chuỗi không lặp lại có thể thấy mọi số từ 1 đến 100 bao gồm:

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

Trong mã Java, bạn sẽ viết:

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

Tìm một gốc nguyên thủy cho một mô-đun cụ thể có thể phức tạp, nhưng chức năng "primroot" của Maple sẽ giúp bạn.


Điều đó thật thú vị, nhưng làm thế nào chúng ta đảm bảo rằng chuỗi được tạo là ngẫu nhiên? Nó dường như không phải vậy. Có vẻ như rất xác định khi có 1,2,4,8,16, ... ở đầu một dãy.
h4nek

Nó không phải là ngẫu nhiên ... nó là giả ngẫu nhiên. Không ai biết cách tạo ra các số thực sự ngẫu nhiên. Nếu bạn không thích mẫu ban đầu, bạn có thể sử dụng cơ sở lớn hơn làm gốc nguyên thủy.
AT - sinh viên

Giả ngẫu nhiên sẽ ổn. Nhưng ở đây, đối với một "phạm vi" đã cho, hàm số của các gốc nguyên thủy và do đó các chuỗi duy nhất bị hạn chế, đặc biệt là đối với các phạm vi nhỏ hơn .. Vì vậy, dường như có một vấn đề với mẫu ví dụ như luôn có một dãy lũy thừa của gốc. Và không nhận được một (có thể) rất khác nhau trong nhiều lần chạy, trừ khi chúng ta áp dụng một số trò tai quái hơn. Tôi đoán nó phụ thuộc vào trường hợp sử dụng. Thay đổi phần đế dù sao cũng là một nâng cấp tốt, mặc dù nó chỉ "thay đổi" kiểu dáng.
h4nek

2

Tôi đến đây từ một câu hỏi khác, đã trùng lặp với câu hỏi này ( Tạo số ngẫu nhiên duy nhất trong java )

  1. Lưu trữ từ 1 đến 100 số trong một Mảng.

  2. Tạo số ngẫu nhiên từ 1 đến 100 dưới dạng vị trí và trả về mảng [vị trí-1] để nhận giá trị

  3. Khi bạn sử dụng một số trong mảng, hãy đánh dấu giá trị là -1 (Không cần duy trì một mảng khác để kiểm tra xem số này đã được sử dụng chưa)

  4. Nếu giá trị trong mảng là -1, hãy lấy lại số ngẫu nhiên để tìm vị trí mới trong mảng.


1

Tôi có giải pháp dễ dàng cho vấn đề này, Với điều này, chúng ta có thể dễ dàng tạo ra n số ngẫu nhiên duy nhất, Logic duy nhất của nó bất kỳ ai cũng có thể sử dụng nó trong bất kỳ ngôn ngữ nào.

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

0

thử thứ này đi

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

Điều này không khác nhiều so với các câu trả lời khác, nhưng cuối cùng thì tôi muốn mảng các số nguyên:

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

0

bạn có thể sử dụng mảng boolean để điền giá trị true nếu giá trị được lấy khác đặt điều hướng qua mảng boolean để nhận giá trị như dưới đây

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

Chọn n số ngẫu nhiên duy nhất từ ​​0 đến 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;
}

Hãy tưởng tượng một danh sách chứa các số từ 0 đến m-1. Để chọn số đầu tiên, chúng tôi chỉ cần sử dụng rand.nextInt(m). Sau đó, xóa số khỏi danh sách. Bây giờ vẫn còn m-1 số, vì vậy chúng tôi gọi rand.nextInt(m-1). Con số chúng tôi nhận được đại diện cho vị trí trong danh sách. Nếu nó nhỏ hơn số đầu tiên, thì nó là số thứ hai, vì phần danh sách trước số đầu tiên không bị thay đổi bằng cách xóa số đầu tiên. Nếu vị trí lớn hơn hoặc bằng số thứ nhất thì số thứ hai là vị trí + 1. Thực hiện thêm một số dẫn xuất, bạn có thể nhận được thuật toán này.

Giải trình

Thuật toán này có độ phức tạp O (n ^ 2). Vì vậy, nó là tốt để tạo ra một lượng nhỏ các số duy nhất từ ​​một tập hợp lớn. Trong khi thuật toán dựa trên xáo trộn cần ít nhất O (m) để thực hiện xáo trộn.

Thuật toán dựa trên xáo trộn cũng cần bộ nhớ để lưu trữ mọi kết quả có thể có để thực hiện xáo trộn, thuật toán này không cần.


0

Bạn có thể sử dụng lớp Bộ sưu tập.

Một lớp tiện ích được gọi là Collections cung cấp các hành động khác nhau có thể được thực hiện trên một tập hợp như ArrayList (ví dụ: tìm kiếm các phần tử, tìm phần tử tối đa hoặc tối thiểu, đảo ngược thứ tự của các phần tử, v.v.). Một trong những hành động mà nó có thể thực hiện là xáo trộn các phần tử. Việc xáo trộn sẽ di chuyển ngẫu nhiên từng phần tử đến một vị trí khác trong danh sách. Nó thực hiện điều này bằng cách sử dụng một đối tượng Ngẫu nhiên. Điều này có nghĩa là đó là ngẫu nhiên xác định, nhưng nó sẽ làm được trong hầu hết các tình huống.

Để xáo trộn ArrayList, hãy thêm nhập Bộ sưu tập vào đầu chương trình và sau đó sử dụng phương pháp Shuffle static. Nó đưa ArrayList được xáo trộn dưới dạng một tham số:

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

0

Mặc dù đó là một chủ đề cũ, nhưng việc thêm một tùy chọn khác có thể không gây hại. (Các hàm lambda JDK 1.8 dường như làm cho nó dễ dàng);

Vấn đề có thể được chia thành các bước sau;

  • Nhận giá trị tối thiểu cho danh sách các số nguyên được cung cấp (để tạo các số ngẫu nhiên duy nhất)
  • Nhận giá trị lớn nhất cho danh sách các số nguyên được cung cấp
  • Sử dụng lớp ThreadLocalRandom (từ JDK 1.8) để tạo các giá trị số nguyên ngẫu nhiên so với các giá trị số nguyên tối thiểu và tối đa được tìm thấy trước đó, sau đó lọc để đảm bảo rằng các giá trị thực sự được chứa trong danh sách được cung cấp ban đầu. Cuối cùng áp dụng phân biệt cho dòng nội để đảm bảo rằng các số được tạo là duy nhất.

Đây là chức năng với một số mô tả:

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

}

Do đó, để nhận 11 số ngẫu nhiên duy nhất cho đối tượng danh sách 'allIntegers', chúng ta sẽ gọi hàm như;

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

Hàm khai báo arrayList mới 'createdUniqueIds' và điền với mỗi số nguyên ngẫu nhiên duy nhất lên đến số lượng cần thiết trước khi trả về.

Lớp PS ThreadLocalRandom tránh giá trị hạt giống chung trong trường hợp các luồng đồng thời.


0

Đây là phương pháp đơn giản nhất để tạo các giá trị ngẫu nhiên duy nhất trong một phạm vi hoặc từ một mảng .

Trong ví dụ này, tôi sẽ sử dụng một mảng được xác định trước nhưng bạn có thể điều chỉnh phương pháp này để tạo các số ngẫu nhiên. Đầu tiên, chúng tôi sẽ tạo một mảng mẫu để lấy dữ liệu của chúng tôi từ đó.

  1. Tạo một số ngẫu nhiên và thêm nó vào mảng mới.
  2. Tạo một số ngẫu nhiên khác và kiểm tra xem nó đã được lưu trữ trong mảng mới chưa.
  3. Nếu không, hãy thêm nó và tiếp tục
  4. nếu không nhắc lại bước.
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);

Bây giờ từ sampleListchúng tôi sẽ tạo ra năm số ngẫu nhiên là duy nhất.

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
}
        

Đây là khái niệm rất đơn giản. Nếu giá trị ngẫu nhiên được tạo đã tồn tại thì chúng tôi sẽ nhắc lại bước này. Điều này sẽ tiếp tục cho đến khi tất cả các giá trị được tạo là duy nhất.

Nếu bạn thấy câu trả lời này hữu ích thì bạn có thể bỏ phiếu vì nó đơn giản về mặt khái niệm so với các câu trả lời khác .


-1

Bạn có thể tạo n số ngẫu nhiên duy nhất từ ​​0 đến n-1 trong java

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

}


-2

Kiểm tra điều này

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
Đưa các tiêu chuẩn java, khả năng đọc và khả năng sử dụng ra ngoài cửa sổ hả?
austin wernli

Mã không phải là một câu trả lời .. Bạn viết một câu trả lời, và sau đó bạn thêm mã để giải thích những gì bạn muốn.
Aditya

-2

Dưới đây là một cách tôi đã sử dụng để tạo số duy nhất luôn luôn. Hàm ngẫu nhiên tạo ra số và lưu trữ nó trong tệp văn bản, sau đó khi kiểm tra nó trong tệp sẽ so sánh nó và tạo số duy nhất mới, do đó theo cách này luôn có một số duy nhất mới.

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;

}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.