I have a problem for an online course I am doing. The question is:
Given an Integer x, write a program which generates random numbers between x and 0 until each number in this range has been generated at least once. Once all numbers in this range have been generated, the program should display the numbers which were generated.
I have written a program which I thought would solve this but am having problems with the checking if a number is in the range. Here is my code so far:
public static void main(String[] args) {
Random generator = new Random();
ArrayList<Integer> range = new ArrayList<Integer>();
ArrayList<Integer> generated = new ArrayList<Integer>();
int x = 10;
int count = 0;
for(int i = 0; i<x+1; i++){
range.add(i);
}
while(range.isEmpty() != true){
int temp = generator.nextInt(x-1);
count++;
generated.add(temp);
if(range.contains(temp)){
range.remove(temp);
}
}
}
}
My idea was to first create two arraylists. The first would hold all numbers between 0 and the given x. The second would contain the random numbers generated. I then fill the range arraylist with the range between 0 and x. My While loop then checks this range list to see if it is empty. If not, it generates a random number, adds it to my second arraylist. I then check if this number is in the range arraylist - if it is it removes it and carries on. The problem I am having is it is running into IndexOutOfBoundsException after a few goes. I think this is because I am removing the generated numbers from the arraylist. Can anyone help me with fixing this
EDIT: I cant use any collections or other APIs. This part of the course is mainly about using Arrays and loops etc, not advanced Java stuff.
remove is an overloaded method, there is remove(int) which removes the item at the index specified and there is remove(T) which removes the first object int the list that is equal to the argument you passed in
since you passed an int to the method not an Integer, the first method is chosen
the simpliest modification to your code is replacing range.remove(temp); with range.remove(range.indexOf(temp)); or range.remove((Integer)temp)
also you have to call generator.nextInt(x+1); or else the program will be stuck in an infinite loop
You can just replace range.remove(temp); with range.removeIf(t -> t == temp);
Random generator = new Random();
ArrayList<Integer> range = new ArrayList<Integer>();
ArrayList<Integer> generated = new ArrayList<Integer>();
int x = 10;
int count = 0;
for(int i = 0; i<x+1; i++){
range.add(i);
}
while(range.isEmpty() != true){
int temp = generator.nextInt(x-1);
count++;
generated.add(temp);
if(range.contains(temp)){
range.removeIf(t -> t == temp);
}
}
OR You can use Iterator to remove from the List
for (Iterator<Integer> it = range.iterator(); it.hasNext(); ) {
Integer obj= it.next();
if (obj == temp) {
// Remove the current element from the iterator and the list.
it.remove();
break;
}
}
One more issue in your logic
int temp = generator.nextInt(x-1); The random number you are generating doesn't contain all the numbers. It should be int temp = generator.nextInt(x+2);
Hope the below will meet your requirement.
Random random = new Random();
int x = 3;
List<Integer> range = new ArrayList<>();
for(int i = 0; i <x+1; i++) {
range.add(i);
}
List<Integer> list = new ArrayList<>();
while (!list.containsAll(range)) {
list.add(random.nextInt(x + 1));
}
System.out.println(list);
Related
Implementation:
private static List<Integer> getRandomDistribution(List<String> unsortedList, int max) {
Random random = new Random();
List<Integer> indexContainer = new ArrayList<>();
for (int i = 0; i < max; i++) {
int index = random.nextInt(max);
// Below is what I don't like,
if (indexContainer.contains(index)) {
i--;
} else {
indexContainer.add(index);
}
}
return indexContainer;
}
So basically its saying that, until I don't find the required unique random number. I will continue the loop, what could happen is it might keep looping for a long time thus increasing the overhead.
Problems:
int index = random.next(max) is what should decide the randomness, also I will have to maintain the ordering. That why I have used List
Secondly, i-- is where I am stuck, because frankly I don't like the implementation.
NOTE:
I will also have to maintain the order within the indexContainer.
Since you are generating a permutation of all the numbers from 0 to max-1, it would make more sense to populate the List with all the numbers from 0 to max-1 and then call Collections.shuffle(list).
Random random = new Random();
List<Integer> indexContainer = new ArrayList<>();
for (int i = 0; i < max; i++) {
indexContainer.add(i);
}
Collections.shuffle(indexContainer, random);
I have an ArrayList which is defined outside the main method, just inside the class StringRandomize:
public static ArrayList<String> countries = new ArrayList<String>();
I also initialized a random object.
Random obj = new Random();
Then I add some Strings to the list:
StringRandomize.countries.add("USA");
StringRandomize.countries.add("GB");
StringRandomize.countries.add("Germany");
StringRandomize.countries.add("Austria");
StringRandomize.countries.add("Romania");
StringRandomize.countries.add("Moldova");
StringRandomize.countries.add("Ukraine");
How do I make those strings appear randomly? I need output like "Germany", "Moldova" and so on.
I need exactly the strings in the output, not their IDs.
Thanks for your help.
You probably want to use something like:
countries.get(Math.abs(new Random().nextInt()) % countries.size());
Or, to avoid creating a new Random object every time, you could use the same one:
Random gen = new Random();
for (int i = 1; i < 10; i++) {
System.out.println(countries.get(Math.abs(gen.nextInt()) % countries.size()));
}
I would use Collections.shuffle(countries) if you wanted a randomized List.
Else a new Random().nextInt(max) like Flavius described.
static void shuffleArray(string[] ar)
{
//set the seed for the random variable
Random rnd = ThreadLocalRandom.current();
//go from the last element to the first one.
for (int i = ar.size()- 1; i > 0; i--)
{
//get a random number till the current position and simply swap elements
int index = rnd.nextInt(i + 1);
// Simple swap
int a = ar[index];
ar[index] = ar[i];
ar[i] = a;
}
}
This way you shuffle the entire array and get the values in a random order but NO duplicate at all. Every single element changes position, so that no matter what element (position) you pick, you get a country from a random position. You can return the entire vector, the positions are random.
This question already has answers here:
Creating random numbers with no duplicates
(20 answers)
best way to pick a random subset from a collection?
(10 answers)
Closed 7 years ago.
I am trying to get this code to run without duplicates but am having no success researching this area.
Its the start of a question I am doing which will ask the user to input the missing element. However, when I generate random elements I am getting duplicates
import java.util.Random;
public class QuestionOneA2 {
public static void main(String[] args) {
String[] fruit = {"orange", "apple", "pear", "bannana", "strawberry", "mango"};
Random numberGenerator = new Random();
for (int i = 0; i < 5; i++) {
int nextRandom = numberGenerator.nextInt(6);
System.out.println(fruit[nextRandom]);
}
}
}
There are many different approaches you can consider, depending on how flexible the algorithm should be.
Taking 5 random elements from a list of 6, is the same as selection 1 element from the list of 6 that you don't choose. This is a very inflexible, but very easy.
Another approach could be to delete the element from the list, and decrease the maximum random number. In this cause I would advice to not use a String[].
When you generate a random number, I suggest adding it into an array.
Then, when you generate your next number, do some sort of search (google for something efficient) to check if that number is already in the array and thus, has been used already.
If it is, generate a new one, if its not, use it.
You can do this by nesting it in a while loop.
Although, from what I can tell from your question, you would be better off just creating a copy of your fruit array using an ArrayList and then, when you generate a random number to select a fruit, simply remove this fruit from this new list and decrement the range of random numbers you are generating.
You can use a Set to validate if the random generated number is duplicate or not. You just have to keep generating randomNumber until you find a unique random and then add it to the Set to prevent the duplicates.
Here is a quick code snippet:
public static void main(String[] args) {
String[] fruit = {"orange", "apple", "pear", "bannana", "strawberry", "mango"};
Random numberGenerator = new Random();
/* Generate A Random Number */
int nextRandom = numberGenerator.nextInt(6);
Set<Integer> validate = new HashSet<>();
/* Add First Randomly Genrated Number To Set */
validate.add(nextRandom);
for (int i = 0; i < 5; i++) {
/* Generate Randoms Till You Find A Unique Random Number */
while(validate.contains(nextRandom)) {
nextRandom = numberGenerator.nextInt(6);
}
/* Add Newly Found Random Number To Validate */
validate.add(nextRandom);
System.out.println(fruit[nextRandom]);
}
}
Output:
mango
apple
strawberry
pear
orange
You can wrap int into 'Interger' and add it to Set. Set holds no duplicates so there will be only unique values in it. So then just check if a Set already has given Integer with Set.contains(Integer).
my personal solution :
private static int[] randomIndexes(int len) {
int[] indexes = new int[len];
for (int i = 0; i < len; i++) {
indexes[i] = i;
}
for (int i = len - 1, j, t; i > 0; i--) {
j = RANDOM.nextInt(i);
t = indexes[j];
indexes[j] = indexes[i];
indexes[i] = t;
}
return indexes;
}
See it in action : https://gist.github.com/GautierLevert/a6881cff798e5f53b3fb
If I understand you correctly, then you want to choose n-1 elements at random from a list of n elements. If yes, then I recommend to choose just one at random and take all the others.
Arrays.shuffle(fruit);
int notThis = numberGenerator.nextInt(6);
for(int i = 0; i < fruit.length; i++)
if(i!=notThis) System.out.println(fruit[i]);
Copy your array into List<String>, then shuffle it, then just pick elements one by one:
List<String> copy = new ArrayList<>(Arrays.asList(fruit));
Collections.shuffle(copy);
for (String f : copy)
System.out.println(f);
I think it will be easier using an ArrayList, and also controlling the generation of the random number as shown below.
import java.util.Random;
public class QuestionOneA2 {
public static void main(String[] args) {
List<String> fruits = new ArrayList<>();
fruits.add("orange");
fruits.add("apple");
fruits.add("pear");
fruits.add("bannana");
fruits.add("strawberry");
fruits.add("mango");
Random numberGenerator = new Random();
int nextRandom;
for (int i = 0; i < 6 ; i++) {
nextRandom = numberGenerator.nextInt(6 - i);
System.out.println(fruits.get(nextRandom));
fruits.remove(nextRandom);
}
}
}
fruit.remove(fruit[nextRandom]);
Maybe, is it the remove sub-method?
Java Arrays: Finding Unique Numbers In A Group of 10 Inputted Numbers
I have a problem that I have looked into Doestovsky's question but from his question, I need to know on how to make the part on finding duplicates into a function of it's own:
java.util.Scanner input = new java.util.Scanner(System.in);
int[] numbers = new int[10];
boolean[] usedBefore = new boolean[10];
// Insert all numbers
for (int i = 0; i < numbers.length; i++) {
// Read number from console
numbers[i] = input.nextInt();
// Check if number was inserted before
usedBefore[i] = false;
for(int k = 0; k < i; k++) {
if(numbers[k] == numbers[i]) {
usedBefore[i] = true;
break;
}
}
}
// Print all numbers that were not inserted before
for(int j = 0; j < numbers.length; j++) {
if(!usedBefore[i]) {
System.out.print(String.valueOf(numbers[j])+" ");
}
}
I have tried this part of this code and it worked but I need this to take the part that find duplicates into a function of it's own that is powered by arrays.
Credits to ThimoKl for creating this code.
Let's try something else, using Treeset, and let's get rid of that for for
import java.util.*;
public class duplicate {
private static TreeSet<Integer> numbers = new TreeSet<Integer>();
private static TreeSet<Integer> duplicates = new TreeSet<Integer>();
public static void main (String[] args) {
Scanner input = new Scanner(System.in);
int n=0;
int numberOfIntToRead=10;
for (int i = 0; i < numberOfIntToRead; i++) {
// Read number from console
n=input.nextInt();
// Check if number was inserted before
checkIfDuplicate(n);
}
// Print all numbers that were not inserted more than one time
for (Integer j : numbers) {
System.out.print(j+" ");
}
}
public static void checkIfDuplicate(int n){
if(!numbers.contains(n) && !duplicates.contains(n)){
numbers.add(n);
}else{
numbers.remove(n);
duplicates.add(n);
}
}
}
But if you really want to use arrays an not a Collection of any sort, then you need to declare your arrays as class members, that way you can put the "for" that checks for duplicates in a function a give it your i, and this way you can also put the "for" that does the printing in a function. and give to it numbers.length. That should do the trick.
You can make use of a Set to make finding duplicates easy:
List<Integer> dups = new ArrayList<>();
Set<Integer> set = new HashSet<>();
for (int i : numbers)
if (!set.add(i))
dups.add(i);
This works because Set#add() returns false if it doesn't change as a result if being called, which happens eggnog the set already contains the number - ie it's a dup.
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);
}