Variable decremantation of a Math.random ensuring non-rrepetitiveness? - java

I understand this is probably a noobie's question, but I can't wrap my head around it for like 30 minutes now.
I do not understand how this code manages to exclude the possibility of repeating a Math.random result.
This part:
chosenNumbers[rundom] = chosenNumbers[biggestNumber - 1];
biggestNumber--;
Somehow ensures that no number will be repeated. Can someone tell me how does it work? Does it change the value of "biggestNumber" for each every loop? And if so, Math.random can still draw a number that even multiplied by a decremented "biggestNumber" will be the exact same number that was drawn before, by multiplying by initially larger "biggestNumber".
Scanner sc = new Scanner(System.in);
System.out.println("How many numbers do you need to draw?");
int numbersToDraw = sc.nextInt();
System.out.println("What is the biggest number?");
int biggestNumber = sc.nextInt();
int[] chosenNumbers = new int[biggestNumber];
for (int i = 0; i < chosenNumbers.length; i++){
chosenNumbers[i] = i + 1;
}
int[] result = new int[numbersToDraw];
for(int i = 0; i < result.length; i++){
int rundom = (int) (Math.random() * biggestNumber);
result[i] = chosenNumbers[rundom];
chosenNumbers[rundom] = chosenNumbers[biggestNumber - 1];
biggestNumber--;
}
Arrays.sort(result);
System.out.println("Choose the following numbers to get so really rich.");
for(int r : result){
System.out.println(r);
}

The code keeps an array of possible values -- chosenNumbers -- and uses a random number as an index into the array. Once the value is used, it removes it from the list. Even if you get the same random number again, the value at that spot will now be from that spot + 1.
For instance, if biggestNumber is 10, the array contains the values {1, 2, 3, ..., 10}.
Say you get random number 2. chosenNumbers[2] is actually 3 (because arrays index at 0), so you add 3 to the output. But then the code shifts chosenNumbers[3] -> [2], [4] -> [3], etc. So the 3 that used to be in [2] is now gone and can't be selected again.

Related

How do I get the code to print random numbers in all the elements of the 2d array?

I got the 2d array to print but with all zero's and the only random number comes up on the bottom right corner
How do I get the code to print random numbers in all the elements of the 2d array?
Here is my code:
public static void main(String[] args) {
int columns = 8;
int rows = 4;
int rLow = 2;
int rHigh = 9;
printRandos(columns, rows, rLow, rHigh);
}
public static void printRandos(int clmn, int rws, int rlow, int rhigh) {
Random rando = new Random();
int randoNum = rlow + rando.nextInt(rhigh);
int[][] randoArray = new int[rws][clmn];
for (int i = 0; i < rws; i++) {
for (int k = 0; k < clmn; k++) {
randoArray[rws - 1][clmn - 1] = randoNum;
System.out.print(randoArray[i][k] + " ");
}
System.out.print("\n");
}
}
for (int i = 0; i < rws; i++)
{
for (int k = 0; k < clmn; k++)
{
int randoNum = rlow + rando.nextInt(rhigh);
randoArray[i][k] = randoNum;
System.out.print(randoArray[i][k]+" ");
}
System.out.print("\n");
}
your mistake inside the inner for loop of the printRandos method. Firstly your random number is outside the loop so your array elements were receiving the same number all the time. Another mistake is that you are assigning the value to the same array element all the time i.e rws-1 and clmn-1 .
inside your inner loop replace it with this:
int randoNum = rlow + rando.nextInt(rhigh);
randoArray[i][k] = randoNum;
System.out.print(randoArray[i][k]+" ");
Your bug is in this line:
randoArray[rws-1][clmn-1] = randoNum;
This stores your random number into randoArray[rws-1][clmn-1] each time, which as you noticed, is the bottom right corner. rws is always 4, and clmn is always 8. So you store the same number there 32 times, which gives the same result as storing it only once.
In the following line you are correctly printing the number from the current array location:
System.out.print(randoArray[i][k]+" ");
An int array comes initialized with all zeroes, and since except for the last corner you have not filled anything into your array, 0 is printed.
Also if you want different random numbers in all the cells, you would need to call rando.nextInt() inside your innermost for loop.
Unless you need this 2-D array for some purpose (which doesn't show from the minimal example code that you have posted), you do not need it for printing a matrix of random numbers, i.e., you may just print the numbers form within your loop without putting them into the array first.
Finally if rhigh should be the highest possible random number in the array, you should use rando.nextInt(rhigh - rlow + 1). With rlow equal to 2 and rhigh equal to 9 this will give numbers in the range from 0 inclusive to 9 - 2 + 1 = 8 exclusive, which means that after adding to rlow = 2 you will get a number in the range from 2 to 10 exclusive, in other words, to 9 inclusive.
I am on purpose leaving to yourself to fix your code based on my comments. I believe your learning will benefit more from working it out yourself.
Your assign the array value outside the array length
int[][] randoArray = new int[rws][clmn];
randoArray[rws][clmn] = randoNum;
Here randoArray[rws] is out of bounds.

array with random ints but no duplicates and first number showing [duplicate]

This question already has answers here:
Creating random numbers with no duplicates
(20 answers)
Closed 1 year ago.
This is probably already asked, but it is a little difficult for me to understand. I created a for loop to add random integers into my array, but when the integer is already in the array, restart the loop. But I keep on getting the same integers into the array + when there already is a duplicate, the array size increases. Does anyone know what I'm doing wrong?
Random r = new Random();
int[] tes = new int[5];
for (int i = 0; i < tes.length; i++) {
int q = r.nextInt(10);
for (int j = 0; j < i; j++) {
if (q == tes[j]){
i=i-1;
}
}
tes[i] = q;
System.out.println(tes[i]);
}
and the output:
If you want a collection without duplicates you should use a Set:
Random r = new Random();
int desirableSize = 5;
Set<Integer> uniques = new HashSet<>(desirableSize);
while(uniques.size() < desirableSize){
uniques.add(r.nextInt(10));
}
System.out.println(uniques);
The add method already ensures that a value is not added if it already exist on the set.
boolean add(E e)
Adds the specified element to this set if it is not already present (optional operation).
I have used HashSet, however if the insertion order is important for you, use instead LinkedHashSet:
As pjs have pointed out the aforementioned approach is good when:
desirableSize is much less than the pool size, but if the
desirableSize is a substantial proportion of pool size you're better
off shuffling the pool and selecting the first desirableSize elements.
Something as follows:
int start = 0;
int end = 10;
int size = 5;
List<Integer> collect = IntStream.rangeClosed(start, end)
.boxed()
.limit(size)
.collect(Collectors.toList());
Collections.shuffle(collect);
System.out.println(collect);
The rational is the following (quoting pjs):
With rejection-based schemes such as repeated attempts to add to a
set, the expected number of iterations is O(poolsize *
log(desirableSize)) with O(desirableSize) storage for the set.
Shuffling is O(poolsize) but requires O(poolsize) storage for the
shuffle. As desirableSize -> poolsize, shuffling wins on expected
iterations and becomes competitive on storage. With partial shuffling
implementations, the number of iterations for shuffling is
O(desirableSize) although the storage remains the same.
Or more informally, the higher it is the unique finite set of numbers that will be pickup from a finite set of possible numbers, the more desirable it is to use the second approach.
For instance, if one generates numbers from 0 to 1000 and is only interested in 5 numbers, since the probability of picking randomly the same numbers is lower, one is better off with the first approach. However, if you would be (instead) interested in 800 numbers, then one would be better off generating and shuffling the 1000 numbers, and extracting the 800 unique values from them.
Memory-wise the first approach is better then second approach, however performance-wise it depends in the context as we have already described.
i dont see a problem.
Your System.out.println(tes[i]); is in loop
your array has only following ints: 5,9,2,7,1
make println in own loop
for (int i = 0; i < tes.length; i++) {
System.out.println(tes[i]);
}
because you make i=i-1; one value is printed many times
I managed to solve it in a different way:
List<Integer> tes = new ArrayList<>(5);
Random r = new Random();
for (int i = 0; i < 5; i++) {
int testNummer = r.nextInt(10);
if(!tes.contains(testNummer)) {
tes.add(testNummer);
System.out.println(testNummer);
}else{
i=i-1;
}
}
this way is more efficient, I have noticed.
Some logic problem
Increment i variable when you store value in array and don't decrement i variable just break inner loop when found duplicate.
when duplicate found then restart outer loop. use if else condition for that
try below code and for simple understanding i have changed outer loop in while
int i = 0;
while(i<5)
{
int q = r.nextInt(10);
System.out.println("random value generated"+ q );
int j=0;
for (;j < i; j++)
{
if (q == tes[j])
{
System.out.println("duplicate value found"+ q );
break;
}
}
if(j!=i)
{
continue;
}
else
{
if(j==i)
{
tes[i] = q;
i=i+1;
}
}
System.out.println("value at "+ tes[i]);
}
If you want an easy way to generate unique values you can do it with a stream.
Random r = new Random();
int minVal = 1;
int upperBound = 20;
int count = 10;
As long as count is less than upperBound - minVal it will finish without duplicates. For very large counts with the appropriate range, it may take some time.
int[] unique = r.ints(minVal, upperBound).distinct().limit(count).toArray();
System.out.println(Arrays.toString(unique));
Prints something like this.
[14, 1, 7, 13, 5, 16, 2, 8, 12, 4]
An easy way to generate random numbers of a fixed range is to simply shuffle the array.
Integer[] vals = new Integer[20];
for (int i = 0; i < vals.length; i++) {
vals[i] = i+1;
}
// Object array will be shuffle since it backs up the list.
Collections.shuffle(Arrays.asList(vals));
System.out.println(Arrays.toString(vals));
Prints something like
[7, 20, 5, 10, 17, 18, 3, 13, 11, 1, 2, 8, 4, 9, 19, 12, 15, 16, 6, 14]

Can someone explain me this code? About user input, scanner etc

Can someone explain to me how this code works?
It lets the user input numbers up until 1000, then it prints the original inputted numbers, the even and the odd, all in a separate array. But I just don't understand the parts where there is gem++ and gem1++ when it outputs the even and odd not the number of the even and odd numbers.
And after putting this
double even[] = new double[gem];
double odd[] = new double [gem1];
why does it need to repeat gem=0 and gem1=0 again? I'm so sorry if I ask too many question, I'm just confused, I just learned java last week.
public class wutt {
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
System.out.print("Enter no. of elements you want in array : ");
int n = s.nextInt();
if (1 <= n && n <= 1000) {
double a[] = new double[n];
int gem = 0, gem1 = 0;
System.out.println("Enter all the elements : ");
for (int i = 0; i < n; i++) {
a[i] = s.nextInt();
if (a[i] % 2 == 0)
gem++;
else
gem1++;
}
double even[] = new double[gem];
double odd[] = new double[gem1];
gem = 0;
gem1 = 0;
for (int i = 0; i < a.length; i++) {
if (a[i] % 2 == 0) {
even[gem] = a[i];
gem++;
} else {
odd[gem1] = a[i];
gem1++;
}
}
System.out.println("Original: " + Arrays.toString(a));
System.out.println("Odd: " + Arrays.toString(odd));
System.out.println("Even: " + Arrays.toString(even));
} else
System.out.print("Invalid input");
}
}
If you want the program stops after the user enters a number greater than 1000 o less than 0 you need to add the break statement in your if condition.
if (size < 0 || size > 1000) {
System.out.println("Size must be between 0 and 1000");
break;
}
the code before double even[] = new double[gem];
double odd[] = new double [gem1]; is trying to get the number of odds occurred and the number of even occurred and put all inputted elements in array a.
after all that ,now what we got is a array of numbers called a containing all the inputted elements. and two numbers called gem and gem1, which contains the number of odds occurred and the number of even occurred.
so
we get gem(numberOfEvens), gem1(numberOfOdds) and list a
next, we need to put all odds from a to a new array called odd[] with size gem1, and
put all evens from a to a new array called even[] with size gem. at this point, the duty of variable gem1 and gem is done. they become useless.
now we need to go through the list and pick the odd and even out and put them in the array one by one in a sequential way. that's why we need two new variables with 0 initialized.
in this case, because gem and gem1 are useless aready, they are reassigned to help manipulate the tree arrays a , odd[] and even[]
So the user inputs the number of elements he/she wants in the array (n)
double a[] = new double[n]; // a is the array that is initialised to accommodate n elements
int gem = 0, gem1 = 0; // gem is the counter for "even" numbers and "gem1" the counter for odd numbers, and like every good counter, they start at 0
System.out.println("Enter all the elements : ");
for (int i = 0; i < n; i++) { // so we ask the user to input n elements
a[i] = s.nextInt(); // here we read every input and put it in the a array
if (a[i] % 2 == 0) // if the new number is even
gem++; // we increase the even counter "gem"
else // otherwise, when it is an odd number
gem1++; // we increase the odd counter
}
double even[] = new double[gem]; // now we create a new array where we want to hold all the even numbers, we do that by telling it how many even numbers we have counted before (gem)
double odd[] = new double[gem1]; // and a new array for all odd numbers (gem1 was our counter)
gem = 0; // now we reinitialise the counters, because we want to start from the beginning
gem1 = 0;
for (int i = 0; i < a.length; i++) { // in order to copy all numbers from the a array into the two other arrays for even and odd numbers, we iterate over the whole length of the a array. i is the index for the "a" array
if (a[i] % 2 == 0) { // ever even number we encounter
even[gem] = a[i]; // we put in the even array
gem++; // while gem, the "even numbers counter" is our index for the "even" array
} else {
odd[gem1] = a[i]; // odd numbers are for the odd array
gem1++; // while the former "odd numbers counter" now serves as our "odd" array index
}
}
and that's pretty much it. First the user inputs all numbers in a single array and simply counts how many odd and how many even numbers where inputted,
then two new arrays are created, one for the even and one for the odd numbers and since we counted them, we know how big these two new arrays have to be.
And finally all numbers are again iterated over and put in their according array.
At the end you have 3 array, one that holds all numbers, one that holds the even numbers and one with only the odd numbers.
EDIT
here are a few minor changes you could make without changing the nature of that method:
double allNumbers[] = new double[n]; // "allNumbers" is way more specific than "a"
int oddCounter = 0; // "oddCounter" instead of "gem"
int evenCounter = 0; // numbers in variables like "gem1" is really bad practice, because numbers don't say anything about the nature of the variable
System.out.println("Enter all the elements : ");
for (int i = 0; i < n; i++) {
allNumbers[i] = s.nextInt();
if (allNumbers[i] % 2 == 0) {
evenCounter++;
} else {
oddCounter++;
}
}
// until here nothing changes but the names
double even[] = new double[evenCounter];
double odd[] = new double[oddCounter];
int oddIndex = 0; // and here we create new variables, instead of reusing old ones
int evenIndex = 0; // there is absolutely no performance gain in reusing primitives like this - it's just confusing
for (int i = 0; i < allNumbers.length; i++) {
if (allNumbers[i] % 2 == 0) {
even[evenIndex++] = allNumbers[i]; // the "++" can be done directly in the first expression. that's just to make it shorter.
} else {
odd[oddIndex++] = allNumbers[i]; // it is not more performant nor easier to read - just shorter
}
}
EDIT (again)
This is how the arrays look like, say when you enter 4 numbers:
gem = 0
gem1 = 0
n = 4 // user said 4
a = [ , , , ] // array a is empty but holds the space for 4 numbers
a = [1, , , ] // user enters 1
^
i=0
gem1 = 1 // 1 is an odd number -> gem1++
a = [1,4, , ] // user entered "4"
^
i=1
gem = 1 // 4 is an even number -> gem++
a = [1,4,2, ] // user entered "2"
^
i=2
gem = 2 // 24 is an even number -> gem++
a = [1,4,2,7] // user entered "7"
^
i=3
gem1 = 2 // 7 is an odd number -> gem1++
then we fill the other arrays
even = [ , ] // gem is 2, so we have 2 even numbers
odd = [ , ] // gem1 is 2, so we have 2 odd numbers
a = [1,4,2,7]
^
i=0
odd[1, ] // for i=0, a[i] is 1, which is an odd number
a = [1,4,2,7]
^
i=1
even = [4, ] // for i=1, a[i] is 4, which is an even number
a = [1,4,2,7]
^
i=2
even = [4,2] // for i=2, a[i] is 2, which is an even number
a = [1,4,2,7]
^
i=3
odd = [1,7] // for i=3, a[i] is 7, which is an odd number
and in the end you have
a = [1,4,2,7]
even = [4,2]
odd = [1,7]

Generating random distinct pair with no diagonals

I want to generate two random pair of integer with no duplicate in an array of length 8 and I don't want any pair in the same diagonal
public static int[] randomizer(int[] v){
int [] a= new int[8];
for (int i = 0; i < a.length; i++) {
a[i] = (int)(Math.random()*9);
for (int j = 0; j < i; j++) {
if (a[i] == a[j]) {
i--;
break;
}
}
}
a[0] = v[0] ;
return a;
}
This is what I have done so far.
If I understood you correctly you want to generate two random sequences of integers with the length of 8 each. Both sequences should not have any number in common, so you want 16 unique random numbers.
Next comes the requirement with the diagonal part - I don't get it. Please specify it more precice, a small example would be nice.
Meanwhile let's solve the first part. Generating 16 unique integers is quite easy. You generate a random number and memorize it. If it was already generated before than reject it and try again. For a fast contains access and add you should use a HashSet. Let's take a look at the following snippet:
public static Set<Integer> randomUniqueNumbers(int amount, int upperBound){
final HashSet<Integer> numbers = new HashSet<>();
final Random rnd = new Random();
// Stop when generated enough numbers
while (numbers.size() < amount) {
final int randomNumber = rnd.nextInt(upperBound);
// Try to add it to the set.
// The method will do nothing if the number was contained already.
numbers.add(randomNumber);
}
return numbers;
}
The method will generate amount many unique numbers and store them in a Set<Integer> that can be iterated and used by your method. The numbers are between 0 (inclusive) and upperBound (exclusive) like with (int)(Math.random() * upperBound) you used.
Note that it is possible that the while-loop does not halt, for example when extremely unlucky or the given parameters contradict. If that is a problem you can count the number of unsuccessful tries and abort with break once it goes beyond a defined upper limit of tries.
You want 16 of those numbers and store them in two arrays of length 8 each. Here's is how you can do this:
final int[] firstSequence = new int[8];
final int[] secondSequence = new int[8];
// Exchange with the correct upperBound, I assume it is 9
final Set<Integer> numbers = randomUniqueNumbers(16, 9);
Iterator<Integer> numberIter = numbers.iterator();
// Fill the first sequence
for (int i = 0; i < 8; i++) {
firstSequence[i] = numberIter.next();
}
// Fill the second sequence
for (int i = 0; i < 8; i++) {
secondSequence[i] = numberIter.next();
}
I think that covers most of your question. Please specify more precise what is missing and I will update the answer.
Also note that randomUniqueNumbers(16, 9) can not halt. It will run forever since it is not possible to generate 16 different numbers out of {0, 1, 2, 3, 4, 5, 6, 7, 8} which are only 9 numbers. Also note that when both parameters are close it will be drastically faster to use another approach where you pre-define {0, 1, 2, 3, 4, 5, 6, 7, 8} and now just permutate this set and then iterate it, like Collections.shuffle(numbers) and then for(Integer number : numbers) { ... }.

Explain what this code is doing

I'm a newbie in java. I was going through some tutorials and came across this code I was not able to understand the code. Please explain what it means.
class Randoms
{
public static void main(String[] args)
{
Random rand = new Random();
int freq[] = new int[7];
for(int roll = 1; roll < 10; roll++)
{
(++freq[1 + rand.nextInt(6)]);
}
...
Line by line:
Random rand = new Random(); create new instance of the Random object, this is responsible for the creation of random numbers.
int[] freq = new int[7]; create a new int array that can store 7 elements, with indices from 0...6. It is worth noting that in Java, the ints stored in the array are initialized to 0. (This is not true for all languages, an example being C, as in C the int arrays initially store memory junk data, and must be explicitly initialized to zero).
for(int roll = 1; roll < 10; roll++) this rolls 9 times (because 1...9, but it's better practice to go from 0)
(++freq[1 + rand.nextInt(6)]); this line is something that you shouldn't ever do in this sort of fashion, because it's a monstrosity as you can see.
Do something like this:
for(int roll = 0; roll < 9; roll++)
{
int randomNumber = rand.nextInt(6); //number between 0...5
int index = 1 + randomNumber; //number between 1...6
freq[index]++; //increment the number specified by the index by 1
//nearly equivalent to freq[index] += 1;
}
So basically it randomizes the number of 9 dice throws, and stores the dice throw count (or so it calls it, frequency) in the array.
Thus, it's simulating 9 dice throws (numbers from 1...6), and each time it "rolls" a particular number, it increases the number stored in the array at that specific location.
So in the end, if you say:
for(int i = 1; i <= 6; i++)
{
System.out.println("Thrown " + freq[i] + " times of number " + i);
}
Then it will be clearly visible what's happened.
(++freq[1 + rand.nextInt(6)]); // this line of code.
The above line of code is pre-incrementing the value of freq[] array at the specified position,i.e., 1+rand.nextInt(6) --- referred value is ++freq[some-position to be evaluated] which we will evaluate below.
This rand.nextInt(6) will generate an integer number lesser than 6 and greater than 0,as it is a pre-defined method of Random Class ,randomly.We can't predict it.
And,then say number generated is 4. SO, 1+rand.nextInt(6)=5.
Hence,your code would simplify to (++freq[1 + rand.nextInt(6)]) OR `(++freq[5]).
So,simplification of this code will be equivalent to a number which equals 1 more than 6th element of array freq[].
// as freq[5] is the 6th element of the array freq[].
Also,there are some other points which SIR David Wallace suggested me to include which I would like to explain a bit more.It goes below :-
++a here ++ is called pre-increment operator and it increases the value of a by 1. There also exists an altered reverse version of it.
a++ here this ++ is called post-increment operator and it also increases the value of a by 1.But,WAIT,you might have thought that there aren't differences,but there are.
For the differences potion,I'd like to suggest to have a reading of What is the difference between pre-increment and post-increment in the cycle (for/while)?, though it is questioned in sense of C++,the same is in Java too!
// Create a new Random Object, this helps you generate random numbers
Random rand = new Random();
// create a integer array with 7 integers
int freq[] = new int[7];
// loop 9 times
for(int roll = 1; roll < 10; roll++)
{
// rand.nextInt(6) generates a number between 0 and 5 (<6). add one to it
// ++ adds one to the integer in the array that is at the index of 1-6.
(++freq[1 + rand.nextInt(6)]);
}
Some strange things about this code:
Roll loop starts at 1 then goes to 10 so at first glance it would seem to loop 10 times but actually runs 9 times.
The ++ inside the loop would generally be located on the right and could lead to some confusion among newer programmers.
freq[1 + rand.nextInt(6)] causes freq[0] to never be used.
At first a new object of the Random-Class and an array with 7 elements are created. Each element of the Array has the value 0. Inside the for-loop you randomly pick element 2 to 7 of the Array and increase its current value by 1. This is done 9 times.
Your code will never pick the first element of the Array which has the index 0.
I would rewrite the code to make it more clear:
Random rand = new Random();
int freq[] = new int[6];
int randomIndex = 0;
for(int roll = 0; roll < 9; ++roll)
{
randomIndex = rand.nextInt(6);
freq[randomIndex] = freq[randomIndex] + 1;
}
This code has not been tested, but it should basicly do the same.

Categories

Resources