Printing random even value between two values using inheritance - java

I am trying to print a list of random even numbers (5 times) using a bounds. Example being from 0 to 30 (including both those numbers). This is what I have so far (this is in its own class):
public int nextEven(int h){
int n = rand.nextEven(h) % 2;
return n;
}
This is where it would print from my main method:
System.out.println("Random Even:");
for (int i = 0; i < 5; i++){
System.out.println(rand.nextEven(30));
}
When I run the program it gives me an error and I am not quite sure how to solve this. This is an example of the desired output of even numbers from 0 to 30:
4
26
12
10
20

It isn't clear why taking the remainder of 2 would yield an even number. Instead, generate a number in the range 0 to h / 2 and then multiply the result of that by 2. Like,
public int nextEven(int h){
int n = ThreadLocalRandom.current().nextInt(1 + (h / 2)); // 0 to (h / 2) inclusive
return n * 2; // n * 2 is even (or zero).
}

What exactly is rand? Is it the Random class or an instance of your own class?
Since you want to do something with inheritance I guess you want to overwrite a method, but if rand is an instance of the java Random class this won't work.
The error probably comes from recursively calling nextEven method forever.
If you could clarify what exactly you want to do?

I see at least two solutions.
The first one supposes that random + 1 = random. I mean, that if you add or subtract a random number you still get a valid random number. That's why you can use Random class to generate a value in the desired period and then add or subtract one it the number is odd.
The second approach is just to generate an array of even values for the desired period. Then take a random value from this array.

The mod operator % will give you the remainder of the first value divided by the second.
value % 2
... will return 0 if value is even, or 1 if value is odd.
Since rand is a reference to an instance of the class containing your code, you have an infinite recursion. What you really need is something like:
public int nextEven(int h){
int evenRandomValue;
do {
evenRandomValue = (int)(Math.random() * (h + 1));
} while(evenRandomValue % 2 == 1);
return evenRandomValue;
}

Here is a quite explicit way to achieve this using streams:
List<Integer> myRandomInts = Random.ints(lower, upper + 1)
.filter(i -> i % 2 == 0)
.limit(5).boxed()
.collect(Collectors.toList());
This can be read as 'generate an infinite stream of random numbers between given bounds, filter out odds, take the first 5, turn into Integer objects and then collect into a list.

Related

Validate if numbers are valid within a given range, depending on used pre-selection

I'm writing a program that generates n number of bonuses, it does well but when it comes to generate their id numbers i am stuck. The program at that point needs the user to tell the program a Min value and a Max value between 10000 and 10000, until there no problem all easy.
The part after it is making me scratch my head because the program needs to know how many numbers can be generated at a given position of the value generated so it's not a fixed range, the ids generated must and only include the numbers that the user specified for every x position and it has to know that so when it's reading the values that are going to be used for that purpose, they get verified for it's corresponding position.
I have tried to use some some conditions for some cases that i have identified within the working program, but i'm actually stuck because it seems like ill have to build a lot of if statements to contain all of the possible types of ids that can occur.
// from left to right the "positions"
int min = 1 0 0 0 0;
int max = 1 0 9 9 9;
int temp = max - min;
// tells how many different digits can be used from 1 to 10 for each position (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
// leftmost position aka first
delta[0] = temp / 10000;
// aka second position
delta[1] = (temp % 10000) / 1000;
// aka third position
delta[2] = ((temp % 10000) % 1000) / 100;
// aka fourth position
delta[3] = (((temp % 10000) % 1000) % 100) / 10;
// aka fifth position
delta[4] = ((((temp % 10000) % 1000) % 100) % 10);
these formulas work as expected, however when a given position resets there is no way for the formulas to say "you can include all 10 digits on this position because it's not just 0, it's 10000 to 10999".
[EDIT]
To clarify the question above, i am required by my teacher to do the following in order to generate the bonuses id numbers:
ask the user a range (inclusive) between 10000 and 99999. this means that i can only generate 5 digit ids for a given amount of bonuses, they should not repeat.
also ask the user numbers allowed for every position within that 5 digits range given, i.e. my range goes from 12000 to 22000, from left to right of the 5 digits that can be generated user says that he only wants the number 1 to appear so that now limits my ids to generate to values from 12000 to 19999... but he can also say that he only wants the number 2 to be at that particular position so the opposite might happen as well (from 20000 to 22000 ids are only possible to be used). this applies for all 5 digits that can be generated at any given range between min and max.
It would be much, much simpler to keep a List of numbers, generate your ids randomly, and compare, like so:
public class IdGenerator {
private static List<Integer> usedIds = new ArrayList<>();
... (other fields and methods here)
public int generateNumber() {
// Check if all ids are used. (Redesign your ID scheme to prevent this situation, otherwise you'll run out of IDs and your application will stop working.
if (usedIds.size() >= 1000) {
throw new IllegalStateException("All allowable IDs used, please free up an ID to continue generation.");
}
// Generate a random ID with a value between 10000 and 10999.
int idCandidate = ThreadLocalRandom.current().nextInt(10000, 10999 + 1);
// ID in use, try again with new number.
if (usedIds.contains(idCandidate) {
return generateNumber();
}
// ID is not taken and can therefore be saved.
usedIds.add(idCandidate);
return idCandidate;
}
}
Even better would to be to use UUIDs, since they are more or less guaranteed to be unique.

How to generate random values where a percentage of them are 0?

I create a random stream
Random random = new Random();
Stream<Integer> boxed = random.ints(0, 100000000).boxed();
But I need 60% of the numbers generated to be 0, while the remaining can be truly random. How can I do it?
EDIT:
And I need only positive numbers and between 0-100
1
2
0
0
9
0
0
1
12
I'll assume the OP wants approximately 60% of the generated values to be zero, and the remaining approximate 40% to be (pseudo-)random values in the range 1-100, inclusive.
The JDK library makes it easy to generate a stream of N different values.
Since there are 100 values in the range [1,100], and this represents 40% of the output, there need to be 150 values that map to zero to cover the remaining 60%. Thus N is 250.
We can create a stream of ints in the rage [0,249] (inclusive) and map the lowest 150 values in this range to zero, leaving the remainder in the range [1,100]. Here's the code:
IntStream is = random.ints(0, 250)
.map(i -> Math.max(i-149, 0));
UPDATE
If the task is to produce exactly 60% zeroes, there's a way to do it, using a variation of an algorithm in Knuth, TAOCP Vol 2, sec 3.4.2, Random Sampling and Shuffling, Algorithm S. (I explain this algorithm in a bit more detail in this other answer.) This algorithm lets one choose n elements at random from a collection of N total elements, making a single pass over the collection.
In this case we're not selecting elements from a collection. Instead, we're emitting a known quantity of numbers, requiring some subset of them to be zeroes, with the remainder being random numbers from some range. The basic idea is that, as you emit numbers, the probability of emitting a zero depends on the quantity of zeroes remaining to be emitted vs. the quantity of numbers remaining to be emitted. Since this is a stream of fixed size, and it has a bit of state, I've opted to implement it using a Spliterator:
static IntStream randomWithPercentZero(int count, double pctZero, int range) {
return StreamSupport.intStream(
new Spliterators.AbstractIntSpliterator(count, Spliterator.SIZED) {
int remainingInts = count;
int remainingZeroes = (int)Math.round(count * pctZero);
Random random = new Random();
#Override
public boolean tryAdvance(IntConsumer action) {
if (remainingInts == 0)
return false;
if (random.nextDouble() < (double)remainingZeroes / remainingInts--) {
remainingZeroes--;
action.accept(0);
} else {
action.accept(random.nextInt(range) + 1);
}
return true;
}
},
false);
}
There's a fair bit of boilerplate, but you can see the core of the algorithm within tryAdvance. If no numbers are remaining, it returns false, signaling the end of the stream. Otherwise, it emits a number, with a certain probability (starting at 60%) of it being a zero, otherwise a random number in the desired range. As more zeroes are emitted, the numerator drops toward zero. If enough zeroes have been emitted, the fraction becomes zero and no more zeroes are emitted.
If few zeroes are emitted, the denominator drops until it gets closer to the numerator, increasing the probability of emitting a zero. If few enough zeroes are emitted, eventually the required quantity of zeroes equals the quantity of numbers remaining, so the value of the fraction becomes 1.0. If this happens, the rest of the stream is zeroes, so enough zeroes will always be emitted to meet the requirement. The nice thing about this approach is that there is no need to collect all the numbers in an array and shuffle them, or anything like that.
Call the method like this:
IntStream is = randomWithPercentZero(1_000_000, 0.60, 100);
This gets a stream of 1,000,000 ints, 60% of which are zeroes, and the remainder are in the range 1-100 (inclusive).
Since the size of the target interval is divisible by ten, you can count on the last digit of generated numbers being uniformly distributed. Hence, this simple approach should work:
Generate numbers in the range 0..1000
If the last digit of the random number r is 0..5, inclusive, return zero
Otherwise, return r / 10
Here is this approach in code:
Stream<Integer> boxed = random.ints(0, 1000).map(r -> r%10 < 6 ? 0 : r/10).boxed();
Demo.
You can use IntStream.map and re-use your Random instance to generate a random number from 0 to 9 inclusive, returning zero if it's in the first 60%, else the generated number:
Stream<Integer> boxed = random.ints(0, 100)
.map(i -> (random.nextInt(10) < 6) ? 0 : i)
.boxed();
Construct 10 objects. 6 of them returns 0 all the time. and rest 4 returns random based on your specs.
Now randomly select one of the object and call
List<Callable<Integer>> callables = new ArrayList<>(10);
for (int i = 0; i < 6; i++) {
callables.add(() -> 0);
}
Random rand = new Random();
for (int i = 6; i < 10; i++) {
callables.add(() -> rand.nextInt());
}
callables.get(rand.nextInt(10)).call();
This is simpler way to implement it. You can optimize it further.
Why not generate an array of those 60% (those are zero values to start with) and just randomly generate the other 40%:
List<Integer> toShuffle = IntStream
.concat(Arrays.stream(new int[60_000_000]),
random.ints(40_000_000, 0, Integer.MAX_VALUE))
.boxed()
.collect(Collectors.toCollection(() -> new ArrayList<>(100_000_000)));
Collections.shuffle(toShuffle);
If you want exactly 60% of zeros and 40% of strictly positive numbers, you can simply use a modulus check:
Stream<Integer> boxed = IntStream.range(0, 100_000_000)
.map(i -> (i % 10 < 6) ? 0 : r.nextInt(Integer.MAX_VALUE) + 1)
.boxed();
You may want to "shuffle" the stream after that to avoid having 6 zeros in a row every ten positions.
You can controll your stream to generate exactly 60% of zero by counting the generated values and producing zero to reach the desired 60%.
public class RandomGeneratorSample {
public static void main(String... strings) {
Random random = new Random();
Controll60PercentOfZero controll60 = new Controll60PercentOfZero();
Stream<Integer> boxed = random.ints(0, 100).map(x -> controll60.nextValueMustBeZero(x) ? 0 : x).boxed();
boxed.forEach(System.out::println);
}
static class Controll60PercentOfZero {
private long count_zero = 1;
private long count_not_zero = 1;
public boolean nextValueMustBeZero(int x) {
if (x == 0) {
count_zero++;
} else {
count_not_zero++;
}
boolean nextValueMustBeZero= (count_zero * 100 / count_not_zero) < 60;
if(nextValueMustBeZero){
count_zero++;
}
return nextValueMustBeZero;
}
}
}
Interesting question.
Most of other answers are very relevant and each one handles it from a different point of view.
I would like to contribute.
To get a Collection (and not a stream) with exactly 60% of 0 and that these appear "pseudo-randomly", you could :
declare and instantiate a List
then loop on the number of elements that you want to add it
inside it, every 6 iterations on 10, you add 0 at a random index in the List. Otherwise, you add a random value at a random index in the List.
The drawback is that about 40 % of the time, nextInt() is invoked twice: once to generate the value and another one to generate the index where inserting the value in the List.
Here is a sample code that generate 1000 elements from 0 to 1000 which exactly 60% are 0 :
Random random = new Random();
List<Integer> values = new ArrayList<>();
for (int i = 0; i < 1000; i++) {
int nextValue = i % 10 < 6 ? 0 : random.nextInt(1000) + 1;
int indexInList = values.size() <= 1 ? 0 : random.nextInt(values.size() - 1);
values.add(indexInList, nextValue);
}

Generate an Array of Random Integers in which Every Element is Different from its Successor and Predecessor in Java

I'm trying to write an alternative version of the Random().nextInt() method that doesn't generate the same number two times in a row. I searched on StackOverflow but, curiously, the methods I found managed to work only when the range of the random values was sufficiently great (greater than 4 if I'm not being wrong).
To be more specific, I'm trying to generate an int[] of 6 random integers k (0 <= k <= 3) in which every element is different both from its successor and predecessor.
Thank you very much.
Possible solution: after generating the next random number, compare it to the previous one. If they are the same, discard the last one and generate a new one.
Here's my quick pseudocode version for you
Generate a random number
Compares that number with the previous number.
If it is the same then repeat steps 1 and 2.
If it is different store the number.
return the number
Note: be sure to not have a range of numbers with only one integer inside or else you might get stuck in a loop.
There is certainly a better/different way of doing this.
Thinking about what I'd do in Python. Something like based on the range you want the ints to be in e.g. 1.100 create an arraylist of those integers and then access the list at random and pop/remove the element from the list. Or create a static list of random numbers then cast to a set to remove duplicates, then wire the nextInt() up to the set.
I've come up with this:
private ArrayList<Integer> MyRandom(int size, int k)
{
ArrayList<Integer> array = new ArrayList<Integer>();
array.add(new Random().nextInt(k));
while (array.size() <= size)
{
int val = new Random().nextInt(k);
if (array.get(array.size() - 1) != val && (!(val == 1 && array.get(array.size() - 1) == 0)) &&
(!(val == 0 && array.get(array.size() - 1) == 1))) array.add(val);
}
return array;
}
Random rand = new Random();
int last = rand.nextInt(3);
for(int i = 0; i < k; i++) {
last = (last +1 + rand.nextInt(2)) % 4
array.add(last)
}
Advantage: you really only generate O(k) values...

Sorting by least significant digit

I am trying to write a program that accepts an array of five four digit numbers and sorts the array based off the least significant digit. For example if the numbers were 1234, 5432, 4567, and 8978, the array would be sorted first by the last digit so the nest sort would be 5432, 1224, 4597, 8978. Then after it would be 1224, 5432, 8978, 4597. And so on until it is fully sorted.
I have wrote the code for displaying the array and part of it for sorting. I am not sure how to write the equations I need to compare each digit. This is my code for sorting by each digit so far:
public static void sortByDigit(int[] array, int size)
{
for(int i = 0; i < size; i++)
{
for(int j = 0; j < size; j++)
{
}
for(i = 0; i < size; i++)
{
System.out.println(array[i]);
}
}
}
I am not sure what to put in the nested for loop. I think I need to use the modulus.
I just wrote this to separate the digits but I don't know how to swap the numbers or compare them.
int first = array[i]%10;
int second = (array[i]%100)/10;
int third = (array[i]%1000)/10;
int fourth = (array[i]%10000)/10;
Would this would go in the for loop?
It seems like your problem is mainly just getting the value of a digit at a certain index. Once you can do that, you should be able to formulate a solution.
Your hunch that you need modulus is absolutely correct. The modulo operator (%) returns the remainder on a given division operation. This means that saying 10 % 2 would equal 0, as there is no remainder. 10 % 3, however, would yield 1, as the remainder is one.
Given that quick background on modulus, we just need to figure out how to make a method that can grab a digit. Let's start with a general signature:
public int getValueAtIdx(int value, int idx){
}
So, if we call getValueAtIdx(145, 2), it should return 1 (assuming that the index starts at the least significant digit). If we call getValueAtIdx(562354, 3), it should return 2. You get the idea.
Alright, so let's start by using figuring out how to do this on a simple case. Let's say we call getValueAtIdx(27, 0). Using modulus, we should be able to grab that 7. Our equation is 27 % x = 7, and we just need to determine x. So 27 divided by what will give us a remainder of 7? 10, of course! That makes our equation 27 % 10 = 7.
Now that's all find and dandy, but how does 10 relate to 0? Well, let's try and grab the value at index 1 this time (2), and see if we can't figure it out. With what we did last time, we should have something like 27 % x = 27 (WARNING: There is a rabbit-hole here where you could think x should be 5, but upon further examination it can be found that only works in this case). What if we take the 10 we used earlier, but square it (index+1)? That would give us 27 % 100 = 27. Then all we have to do is divide by 10 and we're good.
So what would that look like in the function we are making?
public int getValueAtIdx(int value, int idx){
int modDivisor = (int) Math.pow(10, (idx+1));
int remainder = value % modDivisor;
int digit = remainder / (modDivisor / 10);
return digit;
}
Ok, so let's to back to the more complicated example: getValueAtIdx(562354, 3).
In the first step, modDivisor becomes 10^4, which equals 10000.
In the second step, remainder is set to 562354 % 10000, which equals 2354.
In the third and final step, digit is set to remainder / (10000 / 10). Breaking that down, we get remainder / 1000, which (using integer division) is equal to 2.
Our final step is return the digit we have acquired.
EDIT: As for the sort logic itself, you may want to look here for a good idea.
The general process is to compare the two digits, and if they are equal move on to their next digit. If they are not equal, put them in the bucket and move on.

java assigning values to an array

so i'm creating a program in java where you enter scores and it classifies them into deciles (0-9, 10-19, 20-29, ... 80-89, 90-100) and I've got a grasp on how the program is supposed to work but I'm missing one key element. I create an array with 10 elements (one for each decile range). Once the user inputs their score it divides by 10 and then needs to put the score into it's appropriate spot in the array, but that's where I'm lost. It has to do a bunch of things after that, that I understand but how am I supposed to tell the code when someone enters 55 to increase the 50-59 part of the array by 1 and so on?
Um, it sounds like you just want:
bucketedScores[score / 10]++;
Don't you? Or possibly clearer:
bucketedScores[score / 10] = roughScores[score / 10] + 1;
int index = value / 10;
myArray[index] += 1;
FYI, given what you said, you will get an IndexOutOfBoundsException with a score of 100. May need to deal with that.
Try it this way....
bucketedScores[score / 10] = roughScores[score / 10] + 1;
Sounds like
int[] myarray = new int[10];
// Divide and increase the number returned (like 84/10 = 8 in integer division)
myarray[num/10]++
Though 100 would throw it off, you would need a special case for that one.
According to the Question
get into loops say for example i hope you're dividing 100 values 10-10 each. Use for loops and check and categorize it by assigning the input to a temporary variable for each iteration of inputs.
for(int i=0; i<=100; i++)
{
if(a[i] >= 0 && a[i] < 10)
your desired o/p(execution)
else if(a[i] > 10 && a[i] < 20)
your desired o/p(execution)
}
As the range is has 101 values from 0 to 101 you need to do more than divide by 10.
Do you mean like?
int[] scores = new int[10];
int decile = ...
int score = ....
scores[Math.min(9, decile/10)] += score;
This ensures that 100 is mapped to 9. Another solutions is to use (int)(decile/10.1) which would maps 0 to 10 to the first decile.

Categories