Random permutation of integers using a random number generator - java

This is my homework assignment:
Random r = new Random();
public int get100RandomNumber() {
return 1 + r.nextInt(100);
}
You are given a pre-defined function named getrand100() (above) which
returns an integer which is one random number from 1-100. You can call
this function as many times as you want but beware that this function
is quite resource intensive. You cannot use any other random
generator. You cannot change the definition of getrand100().
Output: Print numbers 1-20 in random order. (Not 20 random numbers)
What I have tried..
public class MyClass {
static Random r = new Random();
static HashSet<Integer>;
public static void main(String args[]) {
myMethod();
System.out.println(s);
}
public static void myMethod() {
boolean b = false;
s = new HashSet<Integer>();
int i = getRand100();
if (i >= 20)
i = i % 20;
int j = 0;
int k, l;
while (s.size() <= 20)
{
System.out.println("occurence no" + ++j);
System.out.println("occurence value" + i);
b = s.add(i);
while (!b) {
k = ++i;
if(k<=20)
b = s.add(k);
if(b==true)
break;
if (!b) {
l = --i;
if(i>=1&&i<=20)
b = s.add(l);
if(b==true)
break;
}
}
}
System.out.println(s);
}
public static int getRand100()
{
return r.nextInt(100) + 1;
}
}
Thanks for any help!

I believe you are asking how to use a random number generator to print out the numbers 1 to 20 in a random order. This is also known as a "random permutation". The Fischer-Yates shuffle is such an algorithm.
However, to implement the algorithm, you first of all need a random number generator that can pick one out of N items with equal probability where N ranges from 2 up to the size of the set to shuffle, while you only have one that can pick one out of 100 items with equal probability. That can easily be obtained by a combination of modulo arithmetic and "rerolling".

Assuming you are allowed to use the ArrayList class, I'd recommend filling a list with the numbers you want (1 to 20 in this case), then randomly pick numbers from the list and remove them. Using getRand100() % theList.size() should be sufficiently random for your cause and you only need to call it 19 times. When only one element is left, there's no need to "randomly" pick it from the list anymore. ;-)

I believe that I've come up with a way to convert any number between 1 and n! (assuming the number of items is known) to a unique permutation of n items.
In essence, this allows for an "immediate" randomization of an entire deck without having to use any shuffling algorithms. For now, it runs in O(n^2) and requires using BigInteger packages (ie. in Java or Javascript), but I'm looking for ways to optimize the runtime (although, honestly 2500 iterations is nothing these days anyway). Regardless, when given at least 226 bits of valid, random data, the function is able to generate a shuffled array of 52 integers in under 10 ms.
The method is similar to that used to convert a decimal number to binary (continually dividing by 2, etc). I'm happy to provide my code upon request; I find it interesting that I haven't come across it before.

Related

How can I sort an amount of randomly generated numbers defined by the user in Java?

Hey there Stack Overflow community, so I'm still new to Java but I am trying to learn how to sort. Right now my program creates n amount of random numbers from a range of 1 - 10. Although how I would go about putting these numbers into an array to be sorted, I'm not too sure on. Should i go about doing a bubble sort instead of Arrays.sort?
Here's my code
public static final void main(String aArgs){
//User inputs a number for the amount of random numbers to generate
String UserNumbers = JOptionPane.showInputDialog("How many numbers would you like to generate?");
//The unknown amount of numbers "n" is converted from the "UserNumbers" String to an int
int n = Integer.parseInt(UserNumbers);
//Random number generator generating the amount of numbers as defined by the user
Random randomGenerator = new Random();
for (int idx = 1; idx <= n; ++idx){
int randomInts = randomGenerator.nextInt(10);
//Now to create an array for the random numbers to be put into so they can be sorted
int ArrayToSort[] = new int[n];
ArrayToSort[0] = randomInts;
Arrays.sort(ArrayToSort);
System.out.println(ArrayToSort);
}
}
}
I suspect you are not asking whether to use bubble sort because it's faster/slower then Arrays.sort but instead as Arrays.sort doesn't work for you.
I think this is due to the fact your not putting the random numbers you generated into the array you sort
Instead, try this code:
public static final void main(String args){
//User inputs a number for the amount of random numbers to generate
String userNumbers = JOptionPane.showInputDialog("How many numbers would you like to generate?");
//The unknown amount of numbers "n" is converted from the "userNumbers" String to an int
int n = Integer.parseInt(userNumbers);
//Random number generator generating the amount of numbers as defined by the user
int arrayToSort[] = new int[n];
Random randomGenerator = new Random();
for (int idx = 0; idx < n; ++idx){
arrayToSort[idx] = randomGenerator.nextInt(10);
}
Arrays.sort(arrayToSort);
System.out.println(arrayToSort);
}
The problem with your code is that you are trying to populate an array of size n with random numbers, sort it and then print it, but your code generates in each iteration a random number, allocated an n sized array, put's the random number in slot 0 of the array and sort it, and print it (doint this n times) - which won't get the same effect ofcourse
BTW, Random.nextInt(10) return a random number between 0 and 9, not 1 and 10. to achieve what you want you will need to add 1 to that random value
Arrays.java 's sort method uses quicksort for arrays of primitives and merge sort for arrays of objects. I believe that most of time quicksort is faster than merge sort and costs less memory.
Source: Why does Java's Arrays.sort method use two different sorting algorithms for different types?

Generating Random integers within a range to meet a percentile in java

I am trying to generate random integers within a range to sample a percentile of that range. For example: for range 1 to 100 I would like to select a random sample of 20%. This would result in 20 integers randomly selected for 100.
This is to solve an extremely complex issue and I will post solutions once I get this and a few bugs worked out. I have not used many math packages in java so I appreciate your assistance.
Thanks!
Put all numbers in a arraylist, then shuffle it. Take only the 20 first element of the arraylist:
ArrayList<Integer> randomNumbers = new ArrayList<Integer>();
for(int i = 0; i < 100; i++){
randomNumbers.add((int)(Math.random() * 100 + 1));
}
Collections.shuffle(randomNumbers);
//Then the first 20 elements are your sample
If you want 20 random integers between 1 and one hundred, use Math.random() to generate a value between 0 and 0.999... Then, manipulate this value to fit your range.
int[] random = new int[20];
for(int i =0; i< random.length;i++)
{
random[i] = (int)(Math.random()*100+1);
}
When you multiply Math.random() by 100, you get a value between 0 and 99.999... To this number you add 1, yielding a value between 1.0 and 100.0. Then, I typecasted the number to an integer by using the (int) typecast. This gives a number between 1 and 100 inclusive. Then, store the values into an array.
If you are willing to go with Java 8, you could use some features of lambdas. Presuming that you aren't keeping 20% of petabytes of data, you could do something like this (number is the number of integers in the range to get) it isn't efficient in the slightest, but it works, and is fun if you'd like to do some Java 8. But if this is performance critical, I wouldn't recommend it:
public ArrayList<Integer> sampler(int min, int max, int number){
Random random = new Random();
ArrayList<Integer> generated = new ArrayList<Integer>();
IntStream ints = random.ints(min,max);
Iterator<Integer> it = ints.iterator();
for(int i = 0; i < number; i++){
int k = it.next();
while(generated.contains(k)){
k = it.next();
}
generated.add(k);
}
ints.close();
return generated;
}
If you really need to scale to petabytes of data, you're going to need a solution that doesn't require keeping all your numbers in memory. Even a bit-set, which would compress your numbers to 1 byte per 8 integers, wouldn't fit in memory.
Since you didn't mention the numbers had to be shuffled (just random), you can start counting and randomly decide whether to keep each number or not. Then stream your result to a file or wherever you need it.
Start with this:
long range = 100;
float percentile = 0.20f;
Random rnd = new Random();
for (long i=1; i < range; i++) {
if (rnd.nextFloat() < percentile) {
System.out.println(i);
}
}
You will get about 20 percent of the numbers from 1 to 100, with no duplicates.
As the range goes up, the accuracy will too, so you really wouldn't need any special logic for large data sets.
If an exact number is needed, you would need special logic for smaller data sets, but that's pretty easy to solve using other methods posted here (although I'd still recommend a bit set).

How can I fix the size of randomly 5 generated numbers?

I am randomly generating numbers using java.util.Random. But, I can not keep the length of the numbers fixed. Can you help me please?
To fix the length of a randomly generated number, generally you'll want to fix the random number generation to a range. For instance, if you'd like to generate a 6 digit long random number, you'll want numbers from 100,000 to 999,999. You can achieve this by using the following formula.
Random r = new Random();
int randomNum = r.nextInt((max - min) + 1) + min;
Where max is the maximum number, such as 999999, and min is your minimum number, such as 100000.
EDIT:
Based on your comment, I see that you're trying to generate a 15-digit number containing only 1-5 inclusive. Here is a simple way to do this:
import java.util.Random;
StringBuilder s = new StringBuilder();
Random r = new Random();
for (int i = 0; i < 15; i++) {
s.append(r.nextInt(5) + 1);
}
System.out.println("The random number is: " + s.toString());
As noted by #MichaelT, a 15 digit number will not fit in an integer. If you need to perform an operation on it, you should store it in a long.
long randomLong = Long.valueOf(s.toString()).longValue();
Rather than thinking of generating an integer, think in terms of generating a String of 15 digits, each in the required range.
You can use nextInt(int) to pick each digit.
The first thing to consider is that an int cannot hold 15 digits. It just can't. It can only go up to 232 -1, which is 9 digits long. A long can hold up to 19 digits - but if one wants to solve for the general case, it is necessary to use the BigInteger package instead.
Remember that BigInteger is an immutable object (like String) and thus you must assign the value back when looping.
package com.michaelt.so.random15;
import java.math.BigInteger;
import java.util.Random;
public class Main {
public static void main(String[] args) {
Random r = new Random();
BigInteger result = BigInteger.ZERO;
for(int i = 0; i < 15; i++) {
result = result.multiply(BigInteger.TEN)
.add(BigInteger.valueOf(r.nextInt(5)+1));
}
System.out.println(result.toString());
}
}
It starts out with the value ZERO, and loops through for 15 times, each time first multiplying the value by 10 (another BigInteger preallocated value) and then adds the new value into the 1's position. It does this 15 times.
When done, one can get its value as a string or long or other format - or continue to use it as a BigDecimal (necessary if you should ever decide you want a 20 digit long value).
Runs of the above code produce output such as:
313455131111333
245114532433152
531153533113523
If you're ok using libraries:
RandomStringUtils.random(15, "12345")
would give you Strings like: 124444211351355 of length 15
I just happened to write a post about that (shameless self-advertising link: http://united-coders.com/nico-heid/generating-random-numbers-strings-java/)

How to pick an item by its probability?

I have a list of items. Each of these items has its own probability.
Can anyone suggest an algorithm to pick an item based on its probability?
Generate a uniformly distributed random number.
Iterate through your list until the cumulative probability of the visited elements is greater than the random number
Sample code:
double p = Math.random();
double cumulativeProbability = 0.0;
for (Item item : items) {
cumulativeProbability += item.probability();
if (p <= cumulativeProbability) {
return item;
}
}
So with each item store a number that marks its relative probability, for example if you have 3 items one should be twice as likely to be selected as either of the other two then your list will have:
[{A,1},{B,1},{C,2}]
Then sum the numbers of the list (i.e. 4 in our case).
Now generate a random number and choose that index.
int index = rand.nextInt(4);
return the number such that the index is in the correct range.
Java code:
class Item {
int relativeProb;
String name;
//Getters Setters and Constructor
}
...
class RandomSelector {
List<Item> items = new List();
Random rand = new Random();
int totalSum = 0;
RandomSelector() {
for(Item item : items) {
totalSum = totalSum + item.relativeProb;
}
}
public Item getRandom() {
int index = rand.nextInt(totalSum);
int sum = 0;
int i=0;
while(sum < index ) {
sum = sum + items.get(i++).relativeProb;
}
return items.get(Math.max(0,i-1));
}
}
pretend that we have the following list
Item A 25%
Item B 15%
Item C 35%
Item D 5%
Item E 20%
Lets pretend that all the probabilities are integers, and assign each item a "range" that calculated as follows.
Start - Sum of probability of all items before
End - Start + own probability
The new numbers are as follows
Item A 0 to 25
Item B 26 to 40
Item C 41 to 75
Item D 76 to 80
Item E 81 to 100
Now pick a random number from 0 to 100. Lets say that you pick 32. 32 falls in Item B's range.
mj
You can try the Roulette Wheel Selection.
First, add all the probabilities, then scale all the probabilities in the scale of 1, by dividing each one by the sum. Suppose the scaled probabilities are A(0.4), B(0.3), C(0.25) and D(0.05). Then you can generate a random floating-point number in the range [0, 1). Now you can decide like this:
random number in [0.00, 0.40) -> pick A
in [0.40, 0.70) -> pick B
in [0.70, 0.95) -> pick C
in [0.95, 1.00) -> pick D
You can also do it with random integers - say you generate a random integer between 0 to 99 (inclusive), then you can make decision like the above.
Algorithm described in Ushman's, Brent's and #kaushaya's answers are implemented in Apache commons-math library.
Take a look at EnumeratedDistribution class (groovy code follows):
def probabilities = [
new Pair<String, Double>("one", 25),
new Pair<String, Double>("two", 30),
new Pair<String, Double>("three", 45)]
def distribution = new EnumeratedDistribution<String>(probabilities)
println distribution.sample() // here you get one of your values
Note that sum of probabilities doesn't need to be equal to 1 or 100 - it will be normalized automatically.
My method is pretty simple. Generate a random number. Now since the probabilities of your items are known,simply iterate through the sorted list of probability and pick the item whose probability is lesser than the randomly generated number.
For more details,read my answer here.
A slow but simple way to do it is to have every member to pick a random number based on its probability and pick the one with highest value.
Analogy:
Imagine 1 of 3 people needs to be chosen but they have different probabilities. You give them die with different amount of faces. First person's dice has 4 face, 2nd person's 6, and the third person's 8. They roll their die and the one with the biggest number wins.
Lets say we have the following list:
[{A,50},{B,100},{C,200}]
Pseudocode:
A.value = random(0 to 50);
B.value = random(0 to 100);
C.value = random (0 to 200);
We pick the one with the highest value.
This method above does not exactly map the probabilities. For example 100 will not have twice the chance of 50. But we can do it in a by tweaking the method a bit.
Method 2
Instead of picking a number from 0 to the weight we can limit them from the upper limit of previous variable to addition of the current variable.
[{A,50},{B,100},{C,200}]
Pseudocode:
A.lowLimit= 0; A.topLimit=50;
B.lowLimit= A.topLimit+1; B.topLimit= B.lowLimit+100
C.lowLimit= B.topLimit+1; C.topLimit= C.lowLimit+200
resulting limits
A.limits = 0,50
B.limits = 51,151
C.limits = 152,352
Then we pick a random number from 0 to 352 and compare it to each variable's limits to see whether the random number is in its limits.
I believe this tweak has better performance since there is only 1 random generation.
There is a similar method in other answers but this method does not require the total to be 100 or 1.00.
Brent's answer is good, but it doesn't account for the possibility of erroneously choosing an item with a probability of 0 in cases where p = 0. That's easy enough to handle by checking the probability (or perhaps not adding the item in the first place):
double p = Math.random();
double cumulativeProbability = 0.0;
for (Item item : items) {
cumulativeProbability += item.probability();
if (p <= cumulativeProbability && item.probability() != 0) {
return item;
}
}
A space-costly way is to clone each item the number of times its probability. Selection will be done in O(1).
For example
//input
[{A,1},{B,1},{C,3}]
// transform into
[{A,1},{B,1},{C,1},{C,1},{C,1}]
Then simply pick any item randomly from this transformed list.
Adapted the code from https://stackoverflow.com/a/37228927/11257746 into a general extention method. This will allow you to get a weighted random value from a Dictionary with the structure <TKey, int>, where int is a weight value.
A Key that has a value of 50 is 10 times more likely to be chosen than a key with the value of 5.
C# code using LINQ:
/// <summary>
/// Get a random key out of a dictionary which has integer values treated as weights.
/// A key in the dictionary with a weight of 50 is 10 times more likely to be chosen than an element with the weight of 5.
///
/// Example usage to get 1 item:
/// Dictionary<MyType, int> myTypes;
/// MyType chosenType = myTypes.GetWeightedRandomKey<MyType, int>().First();
///
/// Adapted into a general extention method from https://stackoverflow.com/a/37228927/11257746
/// </summary>
public static IEnumerable<TKey> GetWeightedRandomKey<TKey, TValue>(this Dictionary<TKey, int> dictionaryWithWeights)
{
int totalWeights = 0;
foreach (KeyValuePair<TKey, int> pair in dictionaryWithWeights)
{
totalWeights += pair.Value;
}
System.Random random = new System.Random();
while (true)
{
int randomWeight = random.Next(0, totalWeights);
foreach (KeyValuePair<TKey, int> pair in dictionaryWithWeights)
{
int weight = pair.Value;
if (randomWeight - weight > 0)
randomWeight -= weight;
else
{
yield return pair.Key;
break;
}
}
}
}
Example usage:
public enum MyType { Thing1, Thing2, Thing3 }
public Dictionary<MyType, int> MyWeightedDictionary = new Dictionary<MyType, int>();
public void MyVoid()
{
MyWeightedDictionary.Add(MyType.Thing1, 50);
MyWeightedDictionary.Add(MyType.Thing2, 25);
MyWeightedDictionary.Add(MyType.Thing3, 5);
// Get a single random key
MyType myChosenType = MyWeightedDictionary.GetWeightedRandomKey<MyType, int>().First();
// Get 20 random keys
List<MyType> myChosenTypes = MyWeightedDictionary.GetWeightedRandomKey<MyType, int>().Take(20).ToList();
}
If you don't mind adding a third party dependency in your code you can use the MockNeat.probabilities() method.
For example:
String s = mockNeat.probabilites(String.class)
.add(0.1, "A") // 10% chance to pick A
.add(0.2, "B") // 20% chance to pick B
.add(0.5, "C") // 50% chance to pick C
.add(0.2, "D") // 20% chance to pick D
.val();
Disclaimer: I am the author of the library, so I might be biased when I am recommending it.
All mentioned solutions have linear effort. The following has only logarithmic effort and deals also with unnormalized probabilities. I'd reccommend to use a TreeMap rather than a List:
import java.util.*;
import java.util.stream.IntStream;
public class ProbabilityMap<T> extends TreeMap<Double,T>{
private static final long serialVersionUID = 1L;
public static Random random = new Random();
public double sumOfProbabilities;
public Map.Entry<Double,T> next() {
return ceilingEntry(random.nextDouble()*sumOfProbabilities);
}
#Override public T put(Double key, T value) {
return super.put(sumOfProbabilities+=key, value);
}
public static void main(String[] args) {
ProbabilityMap<Integer> map = new ProbabilityMap<>();
map.put(0.1,1); map.put(0.3,3); map.put(0.2,2);
IntStream.range(0, 10).forEach(i->System.out.println(map.next()));
}
}
You could use the Julia code:
function selrnd(a::Vector{Int})
c = a[:]
sumc = c[1]
for i=2:length(c)
sumc += c[i]
c[i] += c[i-1]
end
r = rand()*sumc
for i=1:length(c)
if r <= c[i]
return i
end
end
end
This function returns the index of an item efficiently.

Random generated number

How would you set up a program using Java to generate a 5 digit number using the following statement:
int n = (int)Math.floor(Math.random()*100000+1)
It also has to print the number generated. I have tried writing this different ways and keep coming up with errors.
There are two ways of looking at your problem. Either you need to make sure the random number generator only produces numbers with exactly five digits (in the range 10000 - 99999) or you need to print the numbers with leading 0s when a number is produced that's too low.
The first approach is best met using Java's Random class.
Random rand = new Random();
int n = rand.nextInt(90000) + 10000;
System.out.println(n);
If you're restricted in some way that you must use the statement in your question, then the second approach is probably what you're after. You can use Java's DecimalFormat class to format a random number with leading zeros before printing.
n = (int)Math.floor( Math.random() * 100000 + 1 );
NumberFormat formatter = new DecimalFormat("00000");
String number = formatter.format(n);
System.out.println("Number with lading zeros: " + number);
One might do:
public class Test {
public static void main(String[] args) {
int n = (int)Math.floor(Math.random()*100000+1);
System.out.println(n);
}
}
However, this really isn't the preferred way of generating random integers. Check out the Random class.
Random r = new Random();
for (;;) {
System.out.println(10000 + r.nextInt(90000));
}
A better idea is to generate the number by successively generating 5 random digits. Making the first digit non-zero ensures that the generated number is always 5-digit. I'm posting pseudocode below, it should be easy to convert it into Java code.
A = List(1,2,3,4,5,6,7,8,9)
B = List(0,1,2,3,4,5,6,7,8,9)
output = 0
output=random.choice(A) //first digit from A, no zeros
for i=0 to 4
output=output*10
output=output+random.choice(B) //next digits from B, can have zero
return output
Look up the API docs for Random if you are stuck.
A way to get a random number 00000 - 99999 is to use the following.
Random r= new Random();
// possibly too obtuse for most readers. ;)
System.out.println((""+(100000+r.nextInt(100000))).substring(1));

Categories