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.
Related
Basically i want to generate random numbers between 1-10, which are put into my set. The thing is that my loop size is from 0 to 9 and it generates random numbers but, once it's 5 numbers, once 7 numbers, once 3 numbers and not exactly 9 numbers. Why?
private static Set<Integer> losowanie() {
Set<Integer> result = new TreeSet<>();
Random random = new Random();
for (int i = 0; i < 10; i++){
result.add(random.nextInt(10) + 1);
}
return result;
}
}
also i was doing the same thing with while loop and it does the same.
Because Set collections cannot have duplicate properties, that is, when you generate numbers, if the same number is generated in the random number, your Set can only hold a unique number.
public static void main(String[] args) {
Set<Integer> result=new TreeSet<>();
for (int i = 0; i < 10; i++) {
result.add(1);
}
//only one data: [1]
System.out.println(result);
result=new TreeSet<>();
for (int i = 0; i <10 ; i++) {
result.add(i);
}
//ten data:[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
System.out.println(result);
}
First of all, your loop indexes from 0 to 9, and that's ten iterations.
So, you might expect ten numbers in your set. But set elements have to be unique, and you are inserting elements randomly selected from a set of only ten possibilities.
The chances of that happening are 10! รท 1010 or about 0.036%. Keep running your program.
If your goal is to have ten different numbers in a random order, do this instead:
List<Integer> result = IntStream.rangeClosed(1, 10)
.boxed()
.collect(Collectors.toList());
Collections.shuffle(random);
I made a code that could generate random numbers, but my issue is that sometimes it would repeat two or three numbers from time to time.
int winnum[] = new int[6];
System.out.print("Lotto winning numbers: ");
for(int i = 0; i < winnum.length; i++){
winnum[i] = 0 + (int)(Math.random() * 42);
System.out.print(winnum[i] + " ");
}
here is my code for generating random numbers
A fairly easy way to do this is to re-imagine this a little bit. Instead of 'generate a random number', think about a deck of cards. You don't 'generate random cards' - you generate (well, print) 52 cards in a specific order and then you randomize their order. Now you can draw cards off the top of the deck and they'll be random, but they cannot repeat.
Do the same thing: Make a list, fill it with all 42 numbers, then shuffle the list, then pull the top 6 numbers off of the list. Voila: Random - and without repetition.
var numbers = new ArrayList<Integer>();
for (int i = 0; i < 42; i++) numbers.add(i);
Collections.shuffle(numbers);
for (int i = 0; i < 6; i++) {
System.out.print(list.get(i) + " ");
}
Here is a real quick way using streams.
Random r = new Random();
r.ints(n,m) - generate a stream of random values between n and m-1 inclusive
distinct - ensure they are unique
limit(n) - limit to n
toArray - return as an array.
int [] result = r.ints(0,42).distinct().limit(6).toArray();
System.out.println(Arrays.toString(result));
prints something like
[37, 19, 28, 31, 15, 12]
You need to check whether the array contains the newly generated random number. If not, you add it, otherwise, keep generating random numbers until one that's not in the array is generated.
To check whether the number is found in the array, you can write the following function that takes the random integer, your array and returns a boolean:
boolean exists = false;
for (int n : winnum) {
if (n == randomInt) {
exists = true;
break;
}
} return exists;
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.
I need to get numbers 1-4 randomly and store it in an arrayList. I have a good start, but I may have an infinite loop because the emulator keeps crashing. The numbers can also not be used more than once.
** lightSelector is a global variable (int lightSelector = 1;)
** generatedOrder is my ArrayList
for (int i = 0; i < 4; i++)
{
lightSelector = 1 + (int)(Math.random() * 4);
generatedOrder.add(lightSelector);
boolean contains = true;
System.out.print(generatedOrder.get(i));
if (!generatedOrder.isEmpty())
{
// Loop until a number is generated that hasn't already been picked
while (contains)
{
if (generatedOrder.contains(lightSelector))
lightSelector = 1 + (int)(Math.random() * 4);
else
{
generatedOrder.add(lightSelector);
contains = false;
break;
}
}
}
}
A more efficient way to get four numbers in a randomly sorted order is to do the following algorithm:
1) Create an int[] array such as {1, 2, 3, 4};
2) For i = 0; i < array.length; ++i, generate a random number, j, between i and array.length-1 inclusive and swap i and j.
Important: That means the possible swaps would be one of 00,01,02,03 followed by one of 11,12,13 followed by one of 22,23 followed by one of 33. This gives you all 4*3*2*1 = 4! ways to permute an array, and that's required for the algorithm to be correct.
(If, for example, you had 4^4 = 256 possible ways for the algorithm to complete, 24 doesn't go into 256 evenly and so some shuffles would be more likely to appear than others.)
This shuffling algorithm has a name: Fisher-Yates Shuffle
EDIT: A good way to generate random numbers in an integer range is to do the following:
1) Generate Random rng = new Random(); exactly once. Don't make a new one ever, because if you make two Random instances in the same time they give exactly the same random number streams.
2) Random has a method, nextInt(n) that returns a random int between 0 and n - 1, so to get random numbers between i and j inclusive do nextInt(j+1-i)+i. To get random numbers between i and j but excluding j, do nextInt(j-i)+i.
API reference: http://docs.oracle.com/javase/1.4.2/docs/api/java/util/Random.html