0から100の間の乱数を取得しようとしています。しかし、シーケンス内で繰り返されるのではなく、一意にする必要があります。たとえば、5つの数字を取得した場合、82,12,53,64,32であり、82,12,53,12,32ではありませんが、同じ数字を連続して生成します。
Random Rand = new Random();
selected = Rand.nextInt(100);
以下に簡単な実装を示します。これにより、1〜10の範囲の3つの一意の乱数が出力されます。
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が現在削除された回答で指摘したように、単一のRandom
インスタンスのみを使用することです。
それが、数値が同一になる原因です。 Random
インスタンスは、ミリ秒単位の現在の時間によってシードされます。特定のシード値、の場合、 'random'インスタンスはまったく同じ疑似ランダム番号のシーケンスを返します。
long
の配列を使用して、わかりやすいブール配列を作成できます。)here のように、100個すべての番号でCollections.shuffle()
を使用し、最初の5つを選択します。
この方法は言及する価値があると思います。
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;
}
セットの一意のプロパティだけでなく、セットへの追加が失敗したときにset.add()
によって返されるブール値のfalseも使用するように、Anandの答えをリファクタリングしました。
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);
}
}
こんな風に作りました。
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);
}
}
これにより、一意の乱数を生成できます......
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);
}
}
これを行う賢い方法の1つは、モジュラスでプリミティブ要素の指数を使用することです。
たとえば、2はプリミティブなルートmod 101です。つまり、2 mod 101の累乗により、1〜100のすべての数値を含む非反復シーケンスが得られます。
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コードでは、次のように記述します。
void randInts() {
int num=1;
for (int ii=0; ii<101; ii++) {
System.out.println(num);
num= (num*2) % 101;
}
}
特定のモジュラスのプリミティブルートを見つけるのは難しい場合がありますが、Mapleの「primroot」関数がこれを行います。
この質問の複製である別の質問からここに来ました( Javaで一意の乱数を生成する )
1〜100個の数値を配列に保存します。
位置として1〜100の乱数を生成し、array [position-1]を返して値を取得します
配列で数値を使用したら、値を-1としてマークします(この数値が既に使用されているかどうかを確認するために別の配列を維持する必要はありません)
配列の値が-1の場合、乱数を再度取得して、配列の新しい場所を取得します。
これは他の答えとそれほど違いはありませんが、最後に整数の配列が必要でした。
Integer[] indices = new Integer[n];
Arrays.setAll(indices, i -> i);
Collections.shuffle(Arrays.asList(indices));
return Arrays.stream(indices).mapToInt(Integer::intValue).toArray();
この問題の簡単な解決策があります。これにより、n個の一意の乱数を簡単に生成できます。そのロジックは誰でも任意の言語で使用できます。
for(int i=0;i<4;i++)
{
rn[i]= GenerateRandomNumber();
for (int j=0;j<i;j++)
{
if (rn[i] == rn[j])
{
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);
}
}
ブール値配列を使用して、値が取得された場合にtrueを埋めることができます。
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からm-1までのn個の一意の乱数を選択します。
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からm-1までの数字を含むリストを想像してください。最初の番号を選択するには、Rand.nextInt(m)
を使用します。次に、リストから番号を削除します。現在はm-1個の数字が残っているため、Rand.nextInt(m-1)
を呼び出します。取得する数値は、リスト内の位置を表します。リストの最初の番号より前の部分は最初の番号を削除しても変更されていないため、最初の番号よりも小さい場合は2番目の番号になります。位置が最初の数値以上の場合、2番目の数値は位置+1です。さらにいくつかの導出を行うと、このアルゴリズムを取得できます。
このアルゴリズムにはO(n ^ 2)の複雑さがあります。そのため、大きなセットから少量の一意の番号を生成するのに適しています。シャッフルベースのアルゴリズムでは、シャッフルを行うには少なくともO(m)が必要です。
また、シャッフルベースのアルゴリズムには、シャッフルを行うために可能な結果をすべて保存するためのメモリが必要ですが、このアルゴリズムは必要ありません。
以下は、常に一意の番号を生成するために使用した方法です。ランダム関数は番号を生成してテキストファイルに保存し、次にファイルでそれをチェックして比較し、新しい一意の番号を生成するため、この方法では常に新しい一意の番号が存在します。
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;
}