I am trying to generate an array filled with random numbers, no duplicates and all of them have to be even and greater than 1. Sadly in my code i often get a "0" in my array but i dont really know how to fix it. Here is the code:
{
public int[] rArray; // our array
RandomArray(int arrayLength, int MaxValue)
{
rArray = new int[arrayLength];
Random randNum = new Random();
for(int p=0; p<arrayLength;p )
for (int i = 0; i <= rArray.length; i )
{
boolean exist = true;
while (exist)
{
exist = false;//
int x = randNum.nextInt(2,MaxValue);
for (int k = 0; k < i; k )
{
if (x == rArray[k] )
{
exist = true;
break;
}
}
if (!exist && x % 2 == 0)
{
rArray[p] = x;
}
}
}
}
CodePudding user response:
The default value for int is 0. When your code returns an odd number you are not assigning any value to the specific index in the array. The issue is happening in the below statements:
if (!exist && x % 2 == 0)
{
rArray[p] = x;
}
Try the below code:
private static int[] getArray(int arrayLength, int maxValue) {
int[] rArray = new int[arrayLength];
Random randNum = new Random();
for (int p = 0; p < arrayLength; p )
for (int i = 0; i <= rArray.length; i ) {
boolean exist = true;
int x = getRandomNumber(randNum, maxValue);
while (exist) {
exist = false;//
for (int k = 0; k < i; k ) {
if (x == rArray[k]) {
exist = true;
break;
}
}
x = getRandomNumber(randNum, maxValue);
}
rArray[p] = x;
}
return rArray;
}
private static int getRandomNumber(Random random, int maxValue) {
while (true) {
int i = random.nextInt(maxValue);
if (i % 2 == 0 && i != 0)
return i;
}
}
Edit: The constructor way of doing it is below: import java.util.Random;
public class RandomArray {
public int[] rArray;
RandomArray(int arrayLength, int MaxValue) {
int[] rArray = new int[arrayLength];
Random randNum = new Random();
for (int p = 0; p < arrayLength; p )
for (int i = 0; i <= rArray.length; i ) {
boolean exist = true;
int x = getRandomNumber(randNum, MaxValue);
while (exist) {
exist = false;//
for (int k = 0; k < i; k ) {
if (x == rArray[k]) {
exist = true;
break;
}
}
x = getRandomNumber(randNum, MaxValue);
}
rArray[p] = x;
}
}
private static int getRandomNumber(Random random, int maxValue) {
while (true) {
int i = random.nextInt(maxValue);
if (i % 2 == 0 && i != 0)
return i;
}
}
}
CodePudding user response:
When using an int[]
of a certain size the values of the array are 0, as that is the default value of an int
(a primitive).
In your loop you are checking if the value doesn't exist and is even, if not you skip over an element in the array leaving the 0.
for (int i = 0; i <= rArray.length; i ) {
boolean exist = true;
while (exist) {
exist = false;//
int x = randNum.nextInt(2,MaxValue);
for (int k = 0; k < i; k ) {
if (x == rArray[k] ) {
exist = true;
break;
}
}
if (!exist && x % 2 == 0) {
rArray[p] = x;
}
}
}
If the random number is 3, that will not exist, and isn't even either. It will leave the while
loop, not having set rArray[p]
and the outer loop will advance to the next one, leaving the 0.
What you should do is first check if the value is even, if not generate a new numnber.
for (int i = 0; i < rArray.length; i ) {
boolean exist = true;
while (exist) {
exist = false;//
int x = 1;
while (((x = randNum.nextInt(2, MaxValue)) % 2) != 0) {}
}
for (int k = 0; k < i; k ) {
if (x == rArray[k] ) {
exist = true;
break;
}
}
if (!exist) {
rArray[i] = x;
}
}
}
Now using streams this would be a lot easier to achieve
rArray= ThreadLocalRandom.current().ints(2, MaxValue)
.filter(it -> (it % 2) == 0)
.distinct().limit(arrayLength).toArray();
Would yield the same result.
CodePudding user response:
How do you get only odd numbers?
You have, in broad strokes, 3 'curves' (as in, a number graph with an X and a Y axis) available to you:
- The linear limited uniform curve
Accessible via .nextInt()
and most of the other methods in the Random class such as .nextBytes()
- these give you a random number between 0 and B (B is, for example, 256 for .nextByte()
, and 5 for .nextInt(5)
, and it is uniformly distributed, meaning: Each number is equally likely to come up.
nextDouble()
.nextDouble()
is a special kid - given that doubles aren't precise, the distribution isn't perfect - you can't say: "It can be any number between 0 and 1" simply because there are an infinite amount of numbers between there, and doubles do not have infinite precision. For random purposes, it's 'anything between 0 and 1, linear uniform', but be aware that going on a mapping spree with this is going to compound the errors inherent in double
math.
- The guassian curve
Accessible via .nextGuassian()
- a gaussian distributed curve. Stuff in the middle is more likely than more extreme numbers. It inherits the same general precision malaise that nextDouble
does.
And those 3 are all you have. Thus, if you have a need for a random distribution that doesn't exactly match any of the above 3, you need to cook up a 'mapping operation' - a function that takes as input one of the above 3 and as output produces random numbers precisely as you desire.
In your specific case, you want 'odd numbers'. That's easy enough to do: Start with .nextInt()
which gives you any number, then, add 1 and multiply by 2. Now you have only odd numbers.
Take nextByte()
to keep things simple: It can only produce 256 different values (0, 1, 2, 3, ...., 255). You could make a table with 2 columns; the left contains each of those numbers. The right contains what happens to it when you toss it through your mapping function. If the right column now is precisely what you desire - voila, you got it.
Thus, make a function:
public static int mapToOdd(int in) {
return 1 in * 2;
}
and then use mapToOdd(rnd.nextInt(maxValue))
.
Why you are getting zeroes.
primitive arrays (and int[]
is a primitive array) start out with all zeroes. When your algorithm does not put a number into each 'cell' of your array, then you get whatever it started out as, which is a zero.
How to fill without replacement
This is actually harder than it sounds. There are 2 options: The one you took is to just generate a number, check if the number is valid, and if not, start over. But you've introduced an error: When you generate an even number, exist
will be false
, but your if (!exist && x % 2 == 0)
function doesn't get entered either - so no value is set (rArray[p]
remains 0), but because exist
is false, your while loop doesn't loop.
Another option is to first generate all numbers possible to generate, store them in an array or list, shuffle the array or list, and then just take the first X elements.
At around the 30% point, efficiency flips over and you want the latter: Imagine you are going to select random numbers from 0-499 inclusive and want to store them in an array with 498 slots, without replacement. Your algorithm (just re-random if it's already there) is going to take AGES for the final few numbers.
CodePudding user response:
There are many ways to do this. One efficient way as suggested in rzwitserloot's answer is to generate the values and then shuffle them.
Here is how that might work.
- here,
maxValue
is the largest value you want to consider. - since you only want every other value, the size of the array would be
maxValue/2
. - after allocating the array, just iterate from 1 to
maxValue/2
filling an array with even values by multiplying theindex by 2
. - now it's time to shuffle the values. If you were using
Integer
arrays you could doCollections.shuffle(Arrays.asList(array))
to shuffle the list which also shuffles the array (since the array backs the list). But that won't work for primitives so included is a simple shuffle routine for primitive arrays ofints
.
It generates a random value from 1 to maxValue
and swaps the value at that location with the value at location maxValue
. Then maxValue
(or its surrogate, in this case i
) is decremented and the process continues, resulting in a shuffled array which is returned.
Note that either all or the first limit
values of the returned array will satisfy the requirement (assuming of course that limit <= maxValue/2
)
public static int[] gen(int maxValue) {
maxValue/=2;
int[] v = new int[maxValue];
for (int i = 1; i <= maxValue; i ) {
v[i-1] = i*2;
}
// time so shuffle.
Random r = new Random();
for (int i = maxValue-1; i >= 0; i--) {
int slot = r.nextInt(i 1);
int t = v[i];
v[i] = v[slot];
v[slot] =t;
}
return v;
}