This question already has answers here:
Generating Unique Random Numbers in Java
(21 answers)
Closed 8 years ago.
I am trying to get non repeat random number from an array of numbers. Each time I try to get random value from that array, it should give me non repeat random number. The previous random values should not be repeated
int[] integer_array = {0,1,2,3,4,5,6,7};
int random_no = should be random number from above array
int random_no2 = should be random number from above array other than random_no
int random_no3 = should be random number from above array other than random_no
and random_no2
Random no from array can be generated for integer_array.length times.
Here is my code:
public static int[] getIndices(int maxValue, int numberOfIndices) {
// The result array.
int[] res = new int[numberOfIndices];
Random rng = new Random();
// A set of already used numbers.
TreeSet<Integer> was = new TreeSet<>();
for (int i = 0; i < numberOfIndices; i++) {
// Generate a new number in range [0..maxValue - i].
// It is a position of a new index in an array of unused values.
int cur = rng.nextInt(maxValue - i);
// Compute its position taking into account all values(used and unused)
// to obtain the real index.
for (int prev : was)
if (cur >= prev)
cur++;
// Add this index to the result array.
was.add(cur);
res[i] = cur;
}
return res;
}
The idea behind it is to generate a position of a new number in array of unused values(this array is not maintained explicitly) and then compute the real index value taking into account already used numbers.
What is good about this method is that it calls nextInt only numberOfIndices times and is guaranteed to generate different numbers regardless of what nextInt returns.
int[] integer_array = {0, 1, 2, 3, 4, 5, 6, 7};
Random r = new Random();
int random_no = r.nextInt(integer_array.length);
System.out.println(random_no);
int random_no2;
do {
random_no2 = r.nextInt(integer_array.length);
} while (random_no2 == random_no);
System.out.println(random_no2);
int random_no3;
do {
random_no3 = r.nextInt(integer_array.length);
} while (random_no3 == random_no || random_no3 == random_no2);
System.out.println(random_no3);
Related
I'm working on a a game where I have to generate an int array of 4 elements randomly. My problem is that the mean of all the array elements always have to be a whole number.
Example :
array 1 {4 , 2 , 3, 7} , the mean of the array is 28,75 which is not what I'm looking for,
array 2 {3 , 7 , 6 , 4} , the mean is 20 which is good
Now I could make a loop where I check if the mean of the randomly generated numbers is a whole number but that doesn't seems like an efficient way to do that.
The game I'm working for is mean sum for those who know it.
If the mean is a whole number, then the sum must be divisible by 4.
int[] n = new int[4];
Pick four numbers, and calculate their sum:
int sum = 0;
for (int i = 0; i < 4; ++i) {
sum += (n[i] = random.nextInt());
}
Calculate the remainder of sum / 4:
int r = sum % 4;
So you now need to adjust the sum so that sum % 4 == 0. You can either:
subtract r from any of the elements of the array:
n[random.nextInt(4)] -= r;
or add 4 - r to any element:
n[random.nextInt(4)] += 4 - r;
Ideone demo
Pick a target mean m and random integers n1, n2.
Your array is [m-n1, m+n1, m-n2, m+n2]. Haven't thought about what the properties of this distribution would be, but it should work.
I believe the following function does what you want, given arguments of how many values you want to generate (n) and what's an upper limit for the sum of the values (max).
private static Random r = new Random();
public static int[] makeSet(int n, int max) {
// The next line guarantees the result is divisible by n
int currentMax = n * (1 + r.nextInt(max / n));
Set<Integer> s = new HashSet<Integer>();
// Generate a set of unique values between 0 and the currentMax,
// containing those bounds
s.add(0);
s.add(currentMax);
do {
s.add(r.nextInt(currentMax));
} while(s.size() <= n);
Integer[] values = new Integer[n + 1];
/*
* Convert to array, sort the results, and find successive
* differences. By construction, those differences WILL sum
* to the currentMax, which IS divisible by the number of
* values generated by differencing!
*/
s.toArray(values);
Arrays.sort(values);
int[] results = new int[n];
for(int i = 0; i < n; ++i) {
results[i] = values[i+1] - values[i];
}
return results;
}
This question already has answers here:
What is the reason for ArrayIndexOutOfBoundsException in my code?
(2 answers)
Closed 7 years ago.
Scenario:
I need to read an array of integers from the standard inputstream, reorder it in such a way that a prime number is always followed by two even numbers ensuring that the prime and even numbers are picked up from the array in the order in which they are present to build the prime-2even set. Any remaining numbers that can't be part of the set can be
placed at the end of the array in the order in which they appear. The input(in multiple lines) and expected output(in multiple lines) as below:
Input:
8 5 9 7 8 5 4 6 8
Expected output:
5 8 4 7 6 8 9 5
Attempt:
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int totalElements = Integer.parseInt(scanner.nextLine());
Integer[] integers = new Integer[totalElements];
Integer[] primeTwoEvens = new Integer[totalElements];
Integer[] leftOvers = new Integer[totalElements];
for (int i = 0; i < integers.length; i++) {
integers[i] = scanner.nextInt();
}
// LOGIC
int notNullCounter = 0; // Variable to track how many elements of integers array has been set to null.
while (notNullCounter != integers.length) { // Repeat this process until all the elements of the integers array are null.
for (int i = 0; i < integers.length; i++) { // Iterate the integers array and check for primeTwoEvens and populate the primeTwoEvens array.
if (integers[i] != null) { // Is the element of integers array to be processed null? If no, proceed.
if (isPrime(integers[i])) { // Is the element of integers array prime? If yes, proceed.
System.out.println(integers[i] + " is prime..."); // Print statement for debugging purpose.
primeTwoEvens[i] = integers[i]; // Since the element of integers array is prime, add it to the primeTwoEvens array.
integers[i] = null; // Set this index of integers array to null.
notNullCounter++; // As one element of integers array has been set to null, increment the null counter.
int evenCounter = 0; // Variable to track even number occurrences.
while (evenCounter != 2) { // Repeat this process until 2 even numbers are not found.
for (int j = ++i; j <= integers.length; j++) { // Iterate the remaining elements of integers array and check for next two even numbers.
if (isEven(integers[j])) { // Is the element of integers array even? If yes, proceed.
System.out.println(integers[j] + " is even..."); // Print statement for debugging purpose.
evenCounter++; // Since the element of integers array is even, increment the even counter.
primeTwoEvens[++i] = integers[j]; // Since the element of integers array is even, add it to the primeTwoEvens array as well.
integers[j] = null; // Set this index of integers array to null.
notNullCounter++; // As one element of integers array has been set to null, increment the null counter.
}
}
}
} /*else { // Element is not prime.
}*/
}
}
//break;
}// End of while
/*System.out.println("############ PRINTING THE FINAL SORTED ARRAY ############");
for (Integer integer : integers) {
System.out.println(integer);
}*/
}
throws me an java.lang.ArrayIndexOutOfBoundsException
Output:
5 is prime...
8 is even...
4 is even...
6 is even...
8 is even...
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 8
at Ideone.main(Ideone.java:125)
Line 125:
if (isEven(integers[j]))
Note: I am restricted to using Java standard API and JDK 7.
How do I solve the problem and the final task?
I think the previous line (before Line 125) should be
for (int j = ++i; j < integers.length; j++)
Not <=
You could try this:
public static void main(String[] args) {
// Read your file (I just copy your example to an array)
Integer[] integers = new Integer[] { 8, 5, 9, 7, 8, 5, 4, 6, 8 };
List<Integer> prime = new ArrayList<Integer>(), even = new ArrayList<Integer>();
List<Integer> other = new ArrayList<Integer>(), ordered = new ArrayList<Integer>();
// Start adding until 1st prime appear
boolean firstPrime = false;
for (Integer number : integers) {
if (isPrime(number)) {
prime.add(number);
firstPrime = true;
} else if (firstPrime && isEven(number)) {
even.add(number);
}
// To have control of the order of appearance
if (firstPrime) other.add(number);
// If I have at least 1 prime and 2 even, then add them
// to my ordered list and remove them from all my other lists
if(prime.size() >= 1 && even.size() >= 2){
ordered.add(prime.get(0));
ordered.add(even.get(0));
ordered.add(even.get(1));
other.remove(prime.get(0));
other.remove(even.get(0));
other.remove(even.get(1));
even.remove(1);
even.remove(0);
prime.remove(0);
}
}
ordered.addAll(other);
System.out.println(ordered);
}
If you run this example, you will have
[5, 8, 4, 7, 6, 8, 9, 5]
I want to generate 6 different random numbers by using Math.random and store them into an array.
How can I make sure that they are different? I know I need to use for-loop to check the array but how...
This is the range. I only need numbers between 1 and 49.
( 1 + (int) (Math.random() * 49) )
In Java 8:
final int[] ints = new Random().ints(1, 50).distinct().limit(6).toArray();
In Java 7:
public static void main(final String[] args) throws Exception {
final Random random = new Random();
final Set<Integer> intSet = new HashSet<>();
while (intSet.size() < 6) {
intSet.add(random.nextInt(49) + 1);
}
final int[] ints = new int[intSet.size()];
final Iterator<Integer> iter = intSet.iterator();
for (int i = 0; iter.hasNext(); ++i) {
ints[i] = iter.next();
}
System.out.println(Arrays.toString(ints));
}
Just a little messier. Not helped by the fact that it's pretty tedious to unbox the Set<Integer> into an int[].
It should be noted that this solution should be fine of the number of required values is significantly smaller than the range. As 1..49 is quite a lot larger than 6 you're fine. Otherwise performance rapidly degrades.
Create a list containing the numbers 1 to 49.
Create a random number x between 0 and the size of the list, take the number being at index x in the list, and remove it from the list.
Repeat the previous step 5 times. And you're done. Note that java.util.Random has a nextInt(int max) method that you should use instead of Math.random().
Note regarding performance: this solution has an advantage compared to the "try until you get 6 different numbers" various solutions: it runs in a O(n) time. It doesn't matter much for 6 unique numbers out of 50, but if you want to get 48 or 49 unique random numbers out of 50, you'll start seeing a difference, because you might have to generate many random numbers before getting one that isn't already in the set.
EDIT:
to reduce the cost induced by the removal of the elements in the list, you could instead simply replace the element at index x with the last element of the list (and at the second iteration, with the element at size - 2, etc.)
You can use a Set.
Set<Integer> s = new HashSet<>();
while(s.size() != 6){
s.add(1 + (int) (Math.random() * 49));
}
Integer[] arr = s.toArray(new Integer[s.size()]);
This is enough to do this in your case because the number of distinct random numbers is relatively small compared to the size of the range you generate them.
Otherwise I would go with #JBNizet approach.
Generate any 6 numbers (not necessarily different). Order them.
a1 <= a2 <= a3 <= a4 <= a5 <= a6
Now take these 6 numbers
a1 < a2 + 1 < a3 + 2 < a4 + 3 < a5 + 4 < a6 + 5
These 6 are different and random.
The idea of this construct comes from some combinatorial proofs.
Its advantage is that it's simple, fast, and deterministic.
I think the time complexity is O(count*log(count)).
I wonder if it can be improved.
import java.util.TreeMap;
public class Test005 {
public static void main(String[] args) {
int count = 6;
int min = 1;
int max = 49;
// random number mapped to the count of its occurrences
TreeMap<Integer, Integer> mp = new TreeMap<Integer, Integer>();
for (int i=0; i<count; i++){
int d = ( min + (int) (Math.random() * (max-count+1)) );
if (!mp.containsKey(d)){
mp.put(d, 0);
}
mp.put(d, mp.get(d) + 1);
}
// now ensure the output numbers are different
int j = 0;
for (int num : mp.keySet()){
int cnt = mp.get(num);
for (int i=0; i<cnt; i++){
System.out.println(num + j);
j++;
}
}
}
}
I've just came up with a small idea for Java 8-.
Set<Integer> set = new LinkedHashSet<>();
while(set.size() != 6)
set.add(rnd.nextInt(49) + 1);
Instead of checking that the array has no duplicates, you can use a bit more smartness while generating the numbers, such that uniqueness is enforced at the outset.
Create a boolean[] as long as your range (49 entries);
generate a random number from the full range;
put that number into your output array;
"cross out" the corresponding index in the boolean[];
now generate another random number, but curtail the range by one (now 48);
instead of directly using that number as output, scan your boolean[], counting all the non-crossed entries. Stop when you reach the count equal to the random number generated in step 5. The number corresponding to that entry is your output number;
go to step 4.
in your case n=6
public static int[] chooseAny(int n){
int[] lottery = new int[n];
int[] chooseFrom = new int[49];
for(int i=1 ; i <= 49 ; i++)
chooseFrom[i-1] = i;
Random rand = new Random();
int N = 49;
int index;
for(int i=0 ; i < n ; i++){
//pick random index
index = rand.nextInt(N);
lottery[i] = chooseFrom[index];
chooseFrom[index] = chooseFrom[N-1];
N--;
}
return lottery;
}
Just keep generating numbers and adding them to the array as long as they are unique; psuedocode:
num = genNextRand()
For (array length)
If (num not in array)
addToArray()
Repeat while length not equal 6
Create a variable last; initialize it to 0.
Next, in a loop x from 0 to 5, create a random number between last+1 and 49-6+x. Store this number in a list, and set last to the number generated this way.
You will end up with an ordered list of 6 random numbers in the range of 1..49 with no repeats.
That code generate numbers from 6 to 0 and save in ArrayList.
If generated number was duplicated the program generate numbers again.
If generated number is different that number is added.
Code:
private ArrayList<Integer> arraylist = new ArrayList<Integer>();
private Random rand = new Random();
public void insertNumber() {
while (true) {
int i = generateNumber();
if(!isGenerateNumberExists(i)){
addNumber(i);
break;
}
}
}
//Generate numbers
private int generateNumber() {
return rand.nextInt(6);
}
//Confirm if that number exists
private boolean isGenerateNumberExists(int y) {
for (int num : arraylist) {
if (num == y) {
return true;
}
}
return false;
}
//Add number to arrayList
private void addNumber(int x) {
arraylist.add(x);
}
I have a method that is not working properly.
The method is supposed to sort a set of numbers from 1 to 20 randomly (each number
must appear just once).
My issue here is that when I run the program, some numbers are repeated several times.
The code is the following:
public static int randomize(int index) {
//This array will hold the 20 numbers.
int[] randomIndex = new int[20];
Random ranNum = new Random();
for (int x = 0; x<20; x++) {
int temp;
//The number is generated randomly and saved in temp.
temp = ranNum.nextInt(20);
//This loop skips the first index.
if (x != 0){
/*Here, the loop is supposed to compare a generated number with
the previous one*/
for (int y = 1; y<=x; y++) {
while(temp == randomIndex[x-y] ) {
/*If the while loop finds that temp variable matches any previous
number it will generate another random number for it until it finds
no matches.*/
temp = ranNum.nextInt(20);
}
}
}
/*Once no match has been found for temp, the number is assigned to an index,
and the loop is executed with a x variable increment.
randomIndex[x] = temp;
}
//Finally the array with the set of random numbers is sent to the main function.
return randomIndex[index];
}
And I got the following output:
19, 19, 5, 16, 6, 2, 18, 1, 15, 1, 5, 19, 11, 4, 18, 0, 5, 18, 10.
So now I have no idea what to do. :C
When you use Random.nextInt(), there's no guarantee that the numbers generated are unique.
You should generate numbers from 1 to 20 first, then shuffle the numbers. Now the question is changed to "How to shuffle the numbers randomly?"
Perhaps you can refer the implementation of JDK Collections.shuffle().
The algorithm for shuffling the numbers are simple:
Pick first element in the array and swap it with a number at random position.
Repeat step 1 until the last element.
You can avoid it by using something like this:
final Random random = new Random();
final HashSet<Integer> integers = new HashSet<>();
while(integers.size() < 20) {
integers.add(random.nextInt(20));
}
System.out.println(integers);
It looks like you're trying to generate your random numbers by rejection -- that is, by comparing each random number with all previously accepted numbers, and re-generating new ones until you find one that is is different from all of them.
As others have mentioned, it would be far more efficient to generate the numbers from 1 to 20, and shuffle them with a random permutation. However, if implemented correctly, your approach should work... eventually.
A random shuffle implementation might look something like this:
for(int i=0; i<20; i++) { // index goes from 0..19
randomIndex[i] = i + 1; // value goes from 1..20
}
for(int i=0; i<20; i++) {
int j = i + ranNum.nextInt(20 - i); // choose random j from i <= j < 20
int temp = randomIndex[i]; // swap elements i and j
randomIndex[i] = randimIndex[j];
randomIndex[j] = temp;
}
The are two reasons why your posted code generates duplicates. First, when you reject a candidate random number and re-generate a new one, you need to compare it against all existing numbers, restarting you inner (y) loop from the beginning. Your existing code doesn't do that.
Second, I believe that the new Random() constructor generates a different seed each time it is called. If so, your randomize() function is generating a completely different random list each time, and returning the selected index from it. In any case, it makes more sense to return the entire array, instead.
I edited your function for generate array from 1 to 20:
public static int[] randomize() {
int[] randomIndex = new int[20];
Random ranNum = new Random();
boolean isAlreadyIn;
boolean isZero;
int x = 0;
while (x < 20) {
isAlreadyIn = false;
isZero = false;
int temp;
temp = ranNum.nextInt(21);
for(int i = 0; i < randomIndex.length; i++){
if(temp == 0)
isZero = true;
if(temp == randomIndex[i])
isAlreadyIn = true;
}
if (!isZero && !isAlreadyIn){
randomIndex[x] = temp;
x++;
}
}
return randomIndex;
}
hope it will be helpful.
Random r1 = new Random();
for(int i=0; i<10; i++){
System.out.print(r1.nextInt(10) + " ");
}
output for one run:
9 7 6 8 3 5 3 3 0 4
why isn't 0-9 generated with equal probability? 3 alone occurs three times, but 1 & 2 zero times.
Empirical probability is not the same as theoretical probability. What you see is the fact that in this case you got 3 3's and no 2's. If you were to run this again, you would get a different set. You would approach the theoretical probability as the number of runs increases.
As others mention, is tossing a coin twice and getting heads both times a sign that the coin is flawed or has an absurd probability of heads? No. If you tossed it a few million times and got all heads? That's a bit more likely then.
If you want to randomize the order of the elements (0-9), you are likely looking for something like a Fisher-Yates Shuffle.
For example:
Random random = new Random();
int[] values = {1, 2, 3, 4, 5};
for(int i = values.length; i > 0; i--) {
int index = random.nextInt(i);
int i1 = values[index];
int i2 = values[i - 1];
values[i - 1] = i1;
values[index] = i2;
}
It seems you don't want random numbers, but a shuffled list of numbers (like a deck of 52 cards).
List<Integer> list = Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
Collections.shuffle(list);
// now display them. They will appear in random order, each exactly once
for (Integer i : list) {
System.out.println(i);
}
From, the OP's comment the requirement becomes more clear:
I want to split a file with multiple lines. The split ratio is for
instance 4:5. For 100 lines, 40 goes to one file and 50 to another
file. And the split must be random
So random numbers are not required, what is required is a random order of numbers 1 to numLines.
This will fulfil the requirement:
public List<Integer> randomLines(final int numLines) {
final List<Integer> lineNumbers = new ArrayList<>(100);
//put the line numbers into the List
//each line occurs exactly once
for (int i = 1; i <= numLines; ++i) {
lineNumbers.add(i);
}
final Random random = new Random();
//Carry out a random reording of the List
Collections.shuffle(lineNumbers, random);
return lineNumbers;
}
In order to test this code I created a simple test case:
Pick a random split point
Create two Set<Integer. for the line numbers of each file
Verify that the Sets have size splitPoint and numLines - splitPoint
This works because a Set can only contain unique items so if there were duplicates then the Sets would have the wrong size:
#Test
public void testRandomLines() {
final App app = new App();
final List<Integer> lineNumbers = app.randomLines(100);
//pick a random split point
final int splitPoint = random.nextInt(lineNumbers.size());
System.out.println(splitPoint);
final Set<Integer> firstFile = new LinkedHashSet<>();
final Set<Integer> secondFile = new LinkedHashSet<>();
for (int i = 0; i < lineNumbers.size(); ++i) {
if (i < splitPoint) {
firstFile.add(lineNumbers.get(i));
} else {
secondFile.add(lineNumbers.get(i));
}
}
assertThat(firstFile.size(), is(splitPoint));
assertThat(secondFile.size(), is(lineNumbers.size() - splitPoint));
}
I hope this answers your question.