我正在尝试获取0到100之间的随机数。但是我希望它们是唯一的,而不是在序列中重复。例如,如果我有5个数字,它们应该分别是82、12、53、64、32,而不是82、12、53、12、32。
Random rand = new Random();
selected = rand.nextInt(100);
我正在尝试获取0到100之间的随机数。但是我希望它们是唯一的,而不是在序列中重复。例如,如果我有5个数字,它们应该分别是82、12、53、64、32,而不是82、12、53、12、32。
Random rand = new Random();
selected = rand.nextInt(100);
Answers:
这是一个简单的实现。这将打印3个唯一的随机数,范围为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));
}
}
}
正如Mark Byers在现已删除的答案中指出的那样,采用原始方法进行修复的第一部分是仅使用单个Random
实例。
这就是导致数字相同的原因。一个Random
实例是由以毫秒为单位的当前时间播种。对于特定的种子值, “随机”实例将返回与伪随机数完全相同的序列。
请注意,
public Integer(int value)
构造函数deprecated
自Java 9起。
第一个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 [] index = new Integer [n]; Arrays.setAll(indices,i-> i); Collections.shuffle(Arrays.asList(indices)); 返回Arrays.stream(indices).mapToInt(Integer :: intValue).toArray(); `
long
其中进行移位和屏蔽以访问各个位。)我觉得这种方法值得一提。
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;
}
我重构了Anand的答案,以不仅使用Set的唯一属性,而且还使用set.add()
了添加到set失败时返回的boolean false 。
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);
}
}
一种聪明的方法是使用模量中的原始元素的指数。
例如,2是原始根mod 101,这意味着2 mod 101的幂提供了一个非重复序列,该序列看到从1到100(包括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);
}
}
您可以使用boolean数组来填充true(如果采用了值),否则请设置boolean数组,以获取值,如下所示
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)
。我们得到的数字代表列表中的位置。如果它小于第一个数字,则为第二个数字,因为删除第一个数字不会更改列表中第一个数字之前的部分。如果位置大于或等于第一个数字,则第二个数字为position + 1。做一些进一步的推导,就可以得到这个算法。
该算法具有O(n ^ 2)复杂度。因此,这对于从大集合中生成少量唯一数是有益的。基于随机播放的算法至少需要O(m)进行随机播放。
同样,基于混洗的算法需要内存来存储进行混洗的所有可能结果,该算法不需要。
您可以使用Collections类。
名为Collections的实用程序类提供了可以在诸如ArrayList之类的集合上执行的不同操作(例如,搜索元素,找到最大或最小元素,颠倒元素的顺序,等等)。它可以执行的动作之一是对元素进行洗牌。随机播放将随机将每个元素移动到列表中的其他位置。它通过使用Random对象来实现。这意味着它是确定性的随机性,但是在大多数情况下都可以。
要改组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 lambda函数似乎很容易实现);
该问题可以分为以下步骤;
这是带有一些描述的函数:
/**
* 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
我们将从中产生五个唯一的随机数。
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
}
从概念上讲这很简单。如果生成的随机值已经存在,那么我们将重复该步骤。这将一直持续到生成的所有值都是唯一的为止。
如果您认为此答案有用,则可以将其投票,因为与其他答案相比,它在概念上非常简单。
检查一下
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
元素后停止。