0〜100の乱数を取得しようとしています。ただし、シーケンスで繰り返されるのではなく、一意である必要があります。たとえば、5つの番号を取得した場合、82,12,53,12,32ではなく82,12,53,64,32になるはずですが、これを使用しましたが、同じ番号が順番に生成されます。
Random rand = new Random();
selected = rand.nextInt(100);
0〜100の乱数を取得しようとしています。ただし、シーケンスで繰り返されるのではなく、一意である必要があります。たとえば、5つの番号を取得した場合、82,12,53,12,32ではなく82,12,53,64,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」インスタンスはまったく同じ一連の疑似乱数を返します。
public Integer(int value)
コンストラクタはdeprecated
Java9以降であることに注意してください。
最初のforループは、次のように簡単に変更できます。
for (int i = 1; i < 11; i++) {
list.add(i);
}
Javaの8+を使用すると、使用できるints
方法をRandom
取得するにはIntStream
、ランダムな値のをdistinct
し、limit
独特のランダムな値の数にストリームを減らすために。
ThreadLocalRandom.current().ints(0, 100).distinct().limit(5).forEach(System.out::println);
Random
代わりに必要に応じてLongStream
sとDoubleStream
sを作成するメソッドもあります。
上記の例が現在実装されているため、範囲内のすべての(または大量の)数値がランダムな順序で必要な場合は、すべての数値をリストに追加してシャッフルし、最初のnを取得する方が効率的です。要求された範囲で乱数を生成し、それらをセットに渡すことによって(Rob Kieltyの回答と同様)、新しい一意の番号を生成する確率が見つかるたびに減少するため、制限に渡された量よりも多くを生成する必要があります。他の方法の例を次に示します。
List<Integer> range = IntStream.range(0, 100).boxed()
.collect(Collectors.toCollection(ArrayList::new));
Collections.shuffle(range);
range.subList(0, 99).forEach(System.out::println);
Arrays#setAll()
で、ストリームよりも少し高速です。したがって、 `Integer []インデックス= new Integer [n]; Arrays.setAll(indices、i-> i); Collections.shuffle(Arrays.asList(indices)); Arrays.stream(indices).mapToInt(Integer :: intValue).toArray();を返します。`
long
個々のビットにアクセスするためにシフトおよびマスクする場所の配列を使用して、クリアしやすいブール配列を作成できます。)pick()
例です。
HashSet
、すでに生成した数値を格納し、その数値をすでに生成したcontains
かどうかをテストするために使用できます。HashSet
おそらくブール配列よりも少し遅くなりますが、少ないメモリを取るだろう。
この方法は言及する価値があると思います。
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);
}
}
SET_SIZE_REQUIRED
十分に大きい場合(たとえば、それを超えると、NUMBER_RANGE / 2
予想される実行時間がはるかに長くなります。
私はこれをそのように作りました。
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の場合、乱数を再度取得して、配列の新しい場所をフェッチします。
この問題の簡単な解決策があります。これにより、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番目の数値はposition +1です。さらに派生を行うと、このアルゴリズムを取得できます。
このアルゴリズムの複雑さはO(n ^ 2)です。したがって、大きなセットから少量の一意の番号を生成するのに適しています。シャッフルベースのアルゴリズムでは、シャッフルを実行するために少なくともO(m)が必要です。
また、シャッフルベースのアルゴリズムには、シャッフルを実行するために考えられるすべての結果を格納するためのメモリが必要です。このアルゴリズムは必要ありません。
Collectionsクラスを使用できます。
Collectionsと呼ばれるユーティリティクラスは、ArrayListなどのコレクションに対して実行できるさまざまなアクションを提供します(たとえば、要素の検索、最大要素または最小要素の検索、要素の順序の逆順など)。実行できるアクションの1つは、要素をシャッフルすることです。シャッフルは、各要素をリスト内の異なる位置にランダムに移動します。これは、ランダムオブジェクトを使用して行います。これは、決定論的なランダム性であることを意味しますが、ほとんどの状況で機能します。
ArrayListをシャッフルするには、Collectionsインポートをプログラムの先頭に追加してから、Shuffle静的メソッドを使用します。ArrayListをパラメーターとしてシャッフルする必要があります。
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);
}
}
古いスレッドですが、別のオプションを追加しても害はないかもしれません。(JDK 1.8ラムダ関数はそれを簡単にするようです);
この問題は、次の手順に分類できます。
説明付きの関数は次のとおりです。
/**
* 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;
}
そのため、「allIntegers」リストオブジェクトの11個の一意の乱数を取得するには、次のような関数を呼び出します。
List<Integer> ids = getUniqueRandomInts(allIntegers,11);
この関数は、新しいarrayList'generatedUniqueIds 'を宣言し、返される前に、必要な数までの一意のランダムな整数をそれぞれ入力します。
PS ThreadLocalRandomクラスは、並行スレッドの場合に共通のシード値を回避します。
これは、範囲内または配列から一意のランダム値を生成するための最も簡単な方法です。です。
この例では、事前定義された配列を使用しますが、この方法を適用して乱数を生成することもできます。まず、データを取得するためのサンプル配列を作成します。
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);
ここから、sampleList
一意の5つの乱数を生成します。
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
}
これは概念的に非常に単純です。生成されたランダム値がすでに存在する場合は、手順を繰り返します。これは、生成されたすべての値が一意になるまで続きます。
この回答が役に立った場合は、他の回答と比較して概念が非常に単純であるため、投票することができます。
ViperCreationによるVeryRandomクラス
ウェブサイト:vipercreation.blogspot.com
使い方 :
レジスターなし(VeryRandomには内部レジスターがあり、クラスがすでに指定された値をスキップするのに役立ちます):
注:最小<= rnd <最大
int rnd = VeryRandom.randomInt(min、max);
double rnd = VeryRandom.randomDouble(min、max);
float rnd = VeryRandom.randomFloat(min、max);
注:randomString / randomChar / ofString()/ ofChar()は指定されたすべてのデータを取得します。つまり、上記のメソッドやofInt / Double / Float()とは異なり、データの最後の値もカウントされます。
String rnd = VeryRandom.randomString(String [] / List);
char rnd = VeryRandom.randomChar(String);
boolean rnd = VeryRandom.randomBoolean();
文字列generateString = VeryRandom.generateString(charsasString、length);
文字列generateString = VeryRandom.generateString(lengthonly);
レジスター付き:
/ *クラスでVeryRandomフィールドを定義し、毎回定義者を呼び出さないことをお勧めします。これにより、レジスターが破損します* /
/ *クラスで* /
VeryRandom rnd;
/ * Androidの「メイン」サイクルまたは「onCreate」サイクル* /
rnd = VeryRandom.ofInt / Float / Double / String / Char()。setRange / Data(int / double / float、int / double / float OR String [] / String);
/ *ランダムな値を取得するたびにこれを呼び出します* /
int / double / float / String / char rndvalue =(int / double / float / String / char)rnd.get();
定義:
VeryRandomは、Java SDKのRandomクラスと同じように機能しますが、繰り返しを減らすために、指定された値を登録します。
Q&A:
Q:新しいVeryRandomを生成することと、ランダム値を生成するために静的メソッドを使用することの違いは何ですか?
A:静的メソッドは内部レジスターを使用せず、新しいVeryRandomフィールドを定義すると、すべてのVeryRandomフィールドに独自のレジスターがあるため、異なるランダムオーダーに対して新しいレジスターを定義することをお勧めします。
ドキュメンテーション :
静的メソッド:
int:VeryRandom.randomInt(int、int)[1番目のintはランダム範囲の最小値であり、2番目のintはランダム範囲の最大値です]
double:VeryRandom.randomDouble(double、double)[最初のdoubleはランダム範囲の最小値であり、2番目のdoubleはランダム範囲の最大値です]
float:VeryRandom.randomFloat(float、float)[1番目のfloatはランダム範囲の最小値であり、2番目のfloatはランダム範囲の最大値です]
文字列:VeryRandom.randomString(String [])[文字列配列は、ランダムな文字列を選択するために指定された文字列です]
文字列:VeryRandom.randomString(List)[リスト文字列はランダムな文字列を選択するために指定された文字列です]
char:VeryRandom.randomChar(String)[文字列はランダムな文字を選択するために指定された文字です]
ブール値:VeryRandom.randomBoolean()
文字列:VeryRandom.generateString(String、int)[文字列はランダムな文字列を生成するために指定された文字であり、intは生成された文字列の長さです]
文字列:VeryRandom.generateString(int)[Intは生成された文字列の長さです]
VeryRandom:VeryRandom.ofInt()[定義メソッド]
VeryRandom:VeryRandom.ofDouble()[定義メソッド]
VeryRandom:VeryRandom.ofFloat()[定義メソッド]
VeryRandom:VeryRandom.ofString()[定義メソッド]
VeryRandom:VeryRandom.ofChar()[定義メソッド]
クラス:タイプ{VeryRandom.Type.INT、VeryRandom.Type.INTEGER、VeryRandom.Type.DOUBLE、VeryRandom.Type.FLOAT、VeryRandom.Type.STRING、VeryRandom.Type.CHAR、VeryRandom.Type.CHARACTER}
非静的メソッド:
VeryRandom:setRange(int、int)[1番目のintはランダム範囲の最小値であり、2番目のintはランダム範囲の最大値です]
VeryRandom:setRange(double、double)[最初のdoubleはランダム範囲の最小値であり、2番目のdoubleはランダム範囲の最大値です]
VeryRandom:setRange(float、float)[1番目のfloatはランダム範囲の最小値であり、2番目のfloatはランダム範囲の最大値です]
VeryRandom:setData(String [])[文字列配列は、ランダムな文字列を選択するために指定された文字列です]
VeryRandom:setData(List)[リスト文字列はランダムな文字列を選択するために指定された文字列です]
VeryRandom:setData(String)[文字列はランダムな文字を選択するために指定された文字です]
オブジェクト:get()[ランダムな値を取得]
文字列:getType()[VeryRandomタイプを取得]
それを得るために:
https://drive.google.com/folderview?id=18eZwJXrbtSHmXlXX8Qq2tJGFbzPZiZe5
これをチェックして
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;
}
}
以下は、私が常に一意の番号を生成するために使用した方法です。ランダム関数は番号を生成してテキストファイルに保存し、次にファイルでチェックするときにそれを比較して新しい一意の番号を生成します。したがって、このようにして常に新しい一意の番号があります。
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;
}
1..100
(そのための有名なアルゴリズムがあります)、最初のn
要素を決定した後で停止します。