This question already has answers here:
Non repeating random numbers
(2 answers)
Closed 8 years ago.
When using the random utility in java, you get some numbers like this: 1271, 34556, 177, etc... What is the simplest way to make it so the digits don't repeat?
You could shuffle the array [1,2,3,4,5,6,7,8,9] and read that as a number.
If you don't want to fix the number of digits, or allow a non-leading zero, it gets more complicated (if you care about some sort of equal distribution).
You could initialize a List with the digits 0-9. Then randomize this list and poll a random amount of elements (between 1 and 9) from this list. Concatenate the digits and you have your number with non-repeating digits.
How about creating a loop that checks if the generated random number meets your requirements.
final Random rnd = new Random();
int n;
do {
n = rnd.nextInt(1000);
} while(containsRepeatingDigits(n));
containsRepeatingDigits can look like this:
boolean containsRepeatingDigits(final int n) {
final boolean digits[] = new boolean[10];
for(char c : String.valueOf(n).toCharArray()) {
final int i = c-'0';
if(digits[i])
return true;
digits[i] = true;
}
return false;
}
You could check if the random number has repeating digits and generate a new one if it does. It's written in C#, but you should be able to convert this to Java real easy.
private static Random rand = new Random();
public static int GenerateNumberNonRepeat()
{
int number;
do
{
number = rand.Next();
} while (IsRepeating(number));
return number;
}
public static bool IsRepeating(int number)
{
string textual = number.ToString();
for (int i = 0; i < textual.Length; i++)
{
for (int j = i + 1; j < textual.Length; j++)
{
if (textual[i] == textual[j])
return true;
}
}
return false;
}
Another way to generate those numbers is to generate arbitrary number, and in case that it contains repeating digits either generate a new one, or remove the repeating digits (by e.g. increment the number until there are no more repeating numbers).
In contrast to proposed shuffle/select approach this has the advantage, that you keep (more or less) the distribution of the original rng.
This code may help you
Set set = new HashSet<Integer>();
Random rand= new Random();
public int getNonRepeatingRandomNumber() {
int intV = rand.nextInt();
if(set.contains(intV)) {
return getNonRepeatingRandomNumber();
}
else {
set.add(intV);
return intV;
}
}
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 want to make a quiz with a switch-case statement. Before entering it I generate a random number between 1 and for example 10. Then there are 10 cases, one for each number. In each of them there is a question, meaning, that the program displays a random question at the beginning. When the question is answered correctly i want the program to pick a random question again by generating a number but not the one who was already picked. How do i do that?
You don't have to use switch for this. Try the following code.
public void play() {
range = new ArrayList<>();
range.addAll(IntStream.rangeClosed(0, questions.size() - 1).boxed().collect(Collectors.toList()));
//Assuming 'questions' is an array list of questions
int index = getQnNumber(); // use this to get a valid question index which is not yet asked
if(index == -1) //means game over
System.out.println("Completed");
else
askQuestion(index);
}
private int getQnNumber() {
int size = range.size();
if(size < 1)
return -1;
Random r = new Random();
int index = r.nextInt(size);
int questionNumber = range.get(index);
range.remove(index);
return questionNumber;
}
You can maintain an ArrayList of the numbers that have been generated already. On every new random generation,
if(!myList.contains(newRandom)){
return newRandom;
}else{
//generate a new random and check
}
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));
}
}
This question already has answers here:
Creating random numbers with no duplicates
(20 answers)
Closed 8 years ago.
I'm working on building one of my fist apps and I'm building a Sudoku mobile game. I've built the random number generator I just cant figure out how to write it so that it only generates numbers between 1-9 (not zero) and each of numbers are only generated once. Here is what I have so far:
package randomNumber;
import java.util.Random;
public class OneToNine {
public static final void main(String... aArgs) {
log ("generating random integers in range 1-9");
Random randomGenerator = new Random();
for (int idx = 1; idx <= 9; ++idx) {
int randomInt = randomGenerator.nextInt(9);
log ("Generated : " + randomInt);
}
log("Done. ");
}
private static void log (String aMessage) {
System.out.println(aMessage);
}
}
Rather than worry about generating the numbers in a random order, you should adjust your approach to shuffling the numbers. You know you will have the numbers 1-9 so do something like this:
public ArrayList<Integer> getRandomOrderedNums(){
ArrayList<Integer> numbers = new ArrayList<Integer>();
for(Integer i = 1; i < 10; i++){
numbers.add(i);
}
Collections.shuffle(numbers);
}
For your second part, to see if the numbers are repeated, you can easily use a data structure such as a HashSet, which is the most efficient to check for repeated values. Let me know if you're not fully comfortable with them. Using the hashset, you can come up with a random number, and check if the set contains this number, and if it does, try again.
With regards to the random number, you can just do randomGenerator.nextInt(9) + 1 so it'll always be from 1-9 (inclusive).
You might want to use a function like this:
public static int getRandInt(int max, int min) {
return new Random().nextInt((max - min) + 1) + min;
}
I need help with this part of my code. This part deals with generating 2 random numbers and using that random number to display a card in each of 2 label boxes simultaneously. The problem here is the random numbers are not getting generated properly and thus cards are not displayed properly (there is repetition, sometimes no display, etc)
Basics of my code:
Let us assume h, which is a variable from another part of the code, is any number between 1 and 53 (each number pertaining to a card). If the random number generated (non-repetition) matches the variable h the timer stops.
So its basically like having a deck of cards and dealing out the cards evenly to 2 people, but here the dealing stops once a number pertaining to a card (number) randomly taken is matched.
(l3,l4 are label names)
Global variables:
Random rng = new Random();
List<Integer> generated = new ArrayList<Integer>();
List<Integer> generated2 = new ArrayList<Integer>();
int l3count;
int l4count;
int Ulim = 53;
int Llim = 1;
int next;
int check;
int h;
int next2;
int Ulim2 = 53;
int Llim2 = 1;
final int p = h;
int delay2 = 1000;
final Timer timer2 = new Timer();
timer2.schedule(new TimerTask(){
public void run(){
for (int i = 1; i < 53; i++)
{
while(true)
{
next = rng.nextInt(Ulim) + Llim;
if (!(generated.contains(next)||generated.contains(next2)))
{
generated.add(next);
break;
}
next2 = rng.nextInt(Ulim2) + Llim2;
if (!(generated.contains(next)||generated.contains(next2)))
{
generated.add(next2);
break;
}
}
String a = Integer.toString(next);
String c = "C:\\Users\\mycompname\\Desktop\\deck\\"+a+".png";
String d = Integer.toString(next2);
String e = "C:\\Users\\mycompname\\Desktop\\deck\\"+d+".png";
for(int j = 1;j<=53;j++)
{
if(j%2==0)
{l3.setIcon(new ImageIcon(c));
}
else
{l4.setIcon(new ImageIcon(e));
}
}
if(next==p||next2==p)
check=10;
break;
}
if(check==10)
timer2.cancel();
timer2.purge();
}
},delay2, 1000);
Any help would be appreciated.
Thanks for your time.
You'd be better off dealing the cards out randomly.
Using the O(n) Knuth Shuffle you can pass along one card at a time, from one array to another.
Each new array you pass the card to will be a different persons' hand.
Keep adding 1 card at a time to each array from the deck array until each player has the number of cards your rules require.
Also, don't rely on random numbers being equal. See stupid-sort. Look for some other pattern instead. Like a random number of cards % cards_left you should stop giving out cards.
Update with code-sample, as per request:
public static void shuffle (int[] array) {
for(int n = array.length; (n > 1);) {
int k = gen.nextInt(n--);
int temp = array[n];
array[n] = array[k];
array[k] = temp;
}
}
The obvious problem is that Random.nextInt generates a number 0 (inclusive) and n (exclusive). So when you pass in a limit of 53, you're generating values between 0 and 52 — that's 53 possible values, and there aren't that many cards. So change the upper limit to 52.
Also, as other answers note, the reason you're getting collisions (dealing the same card to multiple hands), etc. is that you don't want to randomly select the cards. You actually want to randomly shuffle the deck.
Try using a shuffle algorithm instead.