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?
Related
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);
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.
I need to initialize an array of characters with 1000 random characters between [a,..z] and [A,..,Z].
I don’t want do this by first generating only characters between [a,..z] and then only characters in [A...Z] but treat all 52 characters equally.
I know one way to do this is to generate a random number between 0 and 51 and assign it one of the character values.
How would I approach this problem or assign values to the random numbers between 0 and 51?
You have got the interesting code idea.
Here might be the thought.
Take all the a-z and A-Z and store them in an array[].
Randomly generate a number between 1-52 (use API classes for that).
You will get a number in step 2, take it as an array index and pick this index from array[] of chars.
Place that picked char to your desired location/format............
Process it.
Best Regards.
Let me give you some general guidelines. The "one way to do this" you mentioned works. I recommend using a HashMap<E>. You can read more about hashmaps in the docs:
http://docs.oracle.com/javase/7/docs/api/java/util/HashMap.html
Alternatively, you can use another array that contains a - z and A - Z and you can use the index number to refer to them. But in this case I think it makes more sense to use a HashMap<E>.
I think you know how to create a Random object. But if you don't, check out the docs:
http://docs.oracle.com/javase/7/docs/api/java/util/Random.html
So you basically use the nextInt method of the Random class to generate a random number. And you can put that random number into your HashMap or array. And then you just put that character you get into an array that stores the result of the program.
This is the sample work, hope this will work for you
import java.util.ArrayList;
import java.util.Random;
public class RandomNumber {
public static void main(String args[]) {
char c;
ArrayList<Character> character = new ArrayList<Character>();
Random rn = new Random();
for (int i = 0; i < 500; ++i) {
character.add((char) (rn.nextInt(26) + 66));
character.add((char) (rn.nextInt(26) + 97));
}
System.out.println(character);
}
}
The simplest approach would be:
// constant declared in the class
static final int LETTERS_COUNT = 'z'-'a'+1;
char[] randomChars = new char[500];
Random r = new Random();
for(int i=0; i<randomChars.length; i++) {
randomChars[i] = (char)(r.nextInt(LETTERS_COUNT) + (r.nextBoolean() ? 'a' : 'A'));
}
If you don't like accessing random number generator two times, you can generate numbers from 0 to 51:
for(int i=0; i<randomChars.length; i++) {
int num = r.nextInt(LETTERS_COUNT*2);
randomChars[i] = (char)(num >= LETTERS_COUNT ? 'a'+(num-LETTERS_COUNT) : 'A'+num);
}
However I don't see any advantages of this approach. Internally r.nextInt may also change its internal state several times. The distribution should be similar in both cases.
You can this with a function using either arrays or arithemtic.
Note that you can calculate with characters like with numbers, because they are stored as numbers (http://www.asciitable.com/), you will also note that digits, small letters and big letters are stored in sequence so that accessing ranges is pretty easy with a simple for-loop.
private Random r = new Random();
public char randomLetter() {
int randomNumber = this.r.nextInt(52);
if(randomNumber >= 26) {
return (char)(('A'+randomNumber)-26);
} else {
return (char)('a'+randomNumber);
}
}
The version using an array will be faster, but can only be used if the set of possible outcomes is small enough to be stored.
private Random r = new Random();
private static char[] set = new char[52]; //static because we only need 1 overall
static { //this is a static "constructor"
for(int i = 0; i < 26; i++) {
set[i] = (char)('a'+i);
set[i+26] = (char)('A'+i);
}
}
public char fastRandomLetter() {
final int randomNumber = this.r.nextInt(52);
return set[randomNumber];
}
public class ShuffleArray {
public static void main(String[] args) {
int[] array = { 1, 2, 3, 4, 5, 6, 7 };
Random rand = new Random();
for (int i = 0; i < array.length; i++) {
int randomIndexToSwap = rand.nextInt(array.length);
int temp = array[randomIndexToSwap];
array[randomIndexToSwap] = array[i];
array[i] = temp;
}
System.out.println(Arrays.toString(array));
}
}
The following code shows 4 int variables:
int xy1 = 724329;
int xy2 = 714385;
int xy3 = 715440;
int xy4 = 696492;
I'm pretending to code an app that, by opening it, shows one of those numbers (NOT numbers between them) on java console, randomly. I know that Math.Random class can be used to solve these kind of issues, but I don't know what is the proper way to do so.
So, thanks.
Well it sounds like you just want a collection of possible values, and an index between 0 and 3 inclusive:
int[] values = { 724329, 714385, 715440, 696492 };
Random random = new Random(); // Ideally initialize once for the entire app
int index = random.nextInt(4);
int value = values[index];
Place them into an array and use Random to select a number between 0-3 and use it as a key to select the value from the array.
Try this one.
This line
r.nextInt(nums.length)
selects an integer from 0 to nums.length-1.
Then I print out the randomly selected number from the nums array.
I repeat this 20 times just for demonstration purposes.
import java.util.Random;
public class Test015 {
public static void main(String[] args) {
int[] nums = {724329, 714385, 715440, 696492};
Random r = new Random();
for (int i=0; i<20; i++){
int index = r.nextInt(nums.length);
System.out.println("Number randomly chosen: " + nums[index]);
}
}
}
How can I make sure that a random number is only generated once?
For example:
for(int i = 0; i<len; i++)
{
while (rands.contains(rand = r.nextInt(len-2)+1));
rands.add(rand);
System.out.print ("Rand ___ " + rand + "___");
}
How can I make sure that if the number 2 is generated from rand, it wont be generated again?
I apologise if i am not making myself clear enough. Please comment if you require any more information.
Thanks.
You'd have to store all the numbers you've generated, and check the new ones. Use a HashSet for performance' sake:
HashSet<Integer> rands = new HashSet<Integer>();
for(int i = 0; i<3; i++)
{
int rand;
while (rands.contains(rand = r.nextInt(3)))
;
rands.add(rand);
}
You can't really constrain that when using Random API. May be you need to keep a list of already generated numbers and return the number if it is not already generated.
I'm assuming that you want to create a list of numbers from 0-2 in random order (If I'm wrong, let me know)
What you really want is to create a list of those numbers
ArrayList<Integer> randomNums = ArrayList<Integer>() {{ add(0); add(1); add(2); }}
Then use Collections to shuffle that.
Collections.shuffle(randomNums)
You need to use a shuffling algorithm for this. Start with 1. Create an array of Integers from 1 to 1000 (arbitrary Size). Shuffle the array well. keep fetching from the shuffled array till you run out of them. When you are through the 1000, repopulate the array with 1000-2000, shuffle, and use. Repeat the process as many times as you need.
If you just need a stream of non-repeating random numbers in some range you could do something like this:
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
public class RandomNumberStream {
private Iterator<Integer> numbers;
public RandomNumberStream(int range) {
List<Integer> numbersList = new ArrayList<>(range);
for(int i = 0; i < range; i++) {
numbersList.add(i);
}
Collections.shuffle(numbersList);
numbers = numbersList.iterator();
}
public int nextNumber() {
if(!numbers.hasNext()) {
throw new IllegalStateException("No more numbers..."); //you might want to handle this differently
}
return numbers.next();
}
public static void main(String[] args) {
RandomNumberStream rand = new RandomNumberStream(5);
for(int i = 0; i < 5; i++) {
System.out.println(rand.nextNumber());
}
}
}