How to make shuffled number never equal original? (Java) - java

I have an original number (LoadG1). I then produce shuffled versions of this number as seen in the code below. Note: generateG1 is a Random.
int loadG1 = generateG1.nextInt(89999) + 10000;
for (int allrbA = 0; allrbA < 4; allrbA++) {
StringBuilder charLoadG1 = new StringBuilder(String.valueOf(loadG1));
StringBuilder randomLoadG1 = new StringBuilder();
while(charLoadG1.length() != 0) {
int index = generateG1.nextInt(charLoadG1.length());
char c = charLoadG1.charAt(index);
randomLoadG1.append(c);
charLoadG1.deleteCharAt(index);
}
}
if(Integer.valueof(String.valueof(randomLoadG1))==loadG1) {
for (int allrbA = 0; allrbA < 4; allrbA++) {
StringBuilder charLoadG1 = new StringBuilder(String.valueOf(loadG1));
StringBuilder randomLoadG1 = new StringBuilder();
while(charLoadG1.length() != 0) {
int index = generateG1.nextInt(charLoadG1.length());
char c = charLoadG1.charAt(index);
randomLoadG1.append(c);
charLoadG1.deleteCharAt(index);
}
}
This successfully rearranges the numbers in loadG1, seen as the value for randomLoadG1. The issue is, I don't want randomLoadG1 to ever be == to loadG1. This can happen if it is rearranged into the exact same order. I tried using a while loop to sort this out, but it only crashed my app whenever an identical randomLoadG1 was produced.
Can anyone help out with explaining how to get randomLoadG1 (the shuffled version(s) of the original loadG1) to never have the same value as loadG1? Any submitted code is greatly appreciated, many thanks.

Here is a pseudocode implementation:
number1 = random number
do {
number2 = random_shuffle(number1);
} while (number1 == number2)
... where random_shuffle(number1) stands for your existing shuffle algorithm.
Now I don't understand why you can't refactor your existing implementation to follow this pattern, but it should be simple Java programming. If your code is crashing, then you should use a debugger to find out why.

Related

How to randomly combine elements of 2 arrays while making sure to not reuse an element until all have been used at least once?

Essentially I'm writing a program that produces random poems out of an array of nouns and an array of adjectives.
This is accomplished basically using this line
String poem = adjectives[rand.nextInt(3)]+" "+ nouns[rand.nextInt(3)];
Simple enough, but I'm supposed to make sure that it doesn't reuse the same noun or adjective for the next poems until all of them have been used at least once already. I'm not sure how to do that.
Convert the arrays to list, so you can use Collections.shuffle to shuffle them. Once shuffled, you can then simply iterate over them. The values will be random order, and all words will be used exactly once. When you reach the end of an array of words, sort it again, and start from the beginning.
If a poem consists of 1 adjective + 1 noun as in your example, then the program could go something like this:
List<String> adjectives = new ArrayList<>(Arrays.asList(adjectivesArr));
List<String> nouns = new ArrayList<>(Arrays.asList(nounsArr));
Collections.shuffle(adjectives);
Collections.shuffle(nouns);
int aindex = 0;
int nindex = 0;
for (int i = 0; i < 100; ++i) {
String poem = adjectives.get(aindex++) + " " + nouns.get(nindex++);
System.out.println(poem);
if (aindex == adjectives.size()) {
aindex = 0;
Collections.shuffle(adjectives);
}
if (nindex == nouns.size()) {
nindex = 0;
Collections.shuffle(nouns);
}
}
The program will work with other number of adjectives and nouns per poem too.
If you must use an array, you can implement your own shuffle method, for example using the Fisher-Yates shuffle algorithm:
private void shuffle(String[] strings) {
Random random = new Random();
for (int i = strings.length - 1; i > 0; i--) {
int index = random.nextInt(i + 1);
String temp = strings[i];
strings[i] = strings[index];
strings[index] = temp;
}
}
And then rewrite with arrays in terms of this helper shuffle function:
shuffle(adjectives);
shuffle(nouns);
int aindex = 0;
int nindex = 0;
for (int i = 0; i < 100; ++i) {
String poem = adjectives[aindex++] + " " + nouns[nindex++];
System.out.println(poem);
if (aindex == adjectives.length) {
aindex = 0;
shuffle(adjectives);
}
if (nindex == nouns.length) {
nindex = 0;
shuffle(nouns);
}
}
What you can do is make two more arrays, filled with boolean values, that correspond to the adjective and noun arrays. You can do something like this
boolean adjectiveUsed = new boolean[adjective.length];
boolean nounUsed = new boolean[noun.length];
int adjIndex, nounIndex;
By default all of the elements are initialized to false. You can then do this
adjIndex = rand.nextInt(3);
nounIndex = rand.nextInt(3);
while (adjectiveUsed[adjIndex])
adjIndex = rand.nextInt(3);
while (nounUsed[nounIndex]);
nounIndex = rand.nextInt(3);
Note, once all of the elements have been used, you must reset the boolean arrays to be filled with false again otherwise the while loops will run forever.
There are lots of good options for this. One is to just have a list of the words in random order that get used one by one and are then refreshed when empty.
private List<String> shuffledNouns = Collections.EMPTY_LIST;
private String getNoun() {
assert nouns.length > 0;
if (shuffledNouns.isEmpty()) {
shuffledNouns = new ArrayList<>(Arrays.asList(nouns));
Collections.shuffle(wordOrder);
}
return shuffledNouns.remove(0);
}
Best way to do this is to create a shuffled queue from each array, and then just start popping off the front of the queues to build your poems. Once the queues are empty you just generate new shuffled queues and start over. Here's a good shuffling algorithm:
https://en.wikipedia.org/wiki/Fisher–Yates_shuffle
How about keeping two lists for the adjectives and nouns? You can use Collections.shuffle() to order them randomly.
import java.util.*;
class PoemGen {
static List<String> nouns = Arrays.asList("ball", "foobar", "dog");
static List<String> adjectives = Arrays.asList("slippery", "undulating", "crunchy");
public static void main(String[] args) {
for (int i = 0; i < 3; i++) {
System.out.println(String.format("\nPoem %d", i));
generatePoem();
}
}
private static void generatePoem() {
Collections.shuffle(nouns);
Collections.shuffle(adjectives);
int nounIndex = nouns.size() - 1;
int adjectiveIndex = adjectives.size() - 1;
while (nounIndex >= 0 && adjectiveIndex >= 0) {
final String poem = adjectives.get(adjectiveIndex--)+" "+ nouns.get(nounIndex--);
System.out.println(poem);
}
}
}
Output:
Poem 0
crunchy dog
slippery ball
undulating foobar
Poem 1
undulating dog
crunchy ball
slippery foobar
Poem 2
slippery ball
crunchy dog
undulating foobar
Assuming you have the same number of noums and adjectives shuffle both arrays and then merge result. you can shuffle the arrays multiple times if you need (once you get to the end)
shuffleArray(adjectives);
shuffleArray(nouns);
for(int i=0;i<3;i++) {
String poem = adjectives[i] + " " + nouns[i];
}
A simple method to shuffle the arrays:
static void shuffleArray( String[] data) {
for (int i = data.length - 1; i > 0; i--) {
int index = rnd.nextInt(i + 1);
int aux = data[index];
data[index] = data[i];
data[i] = aux;
}
}
This might be overkill for this specific problem but it's an interesting alternative in my opinion:
You can use a linear congruential generator (LCG) to generate the random numbers instead of using rand.nextInt(3). An LCG gives you a pseudo-random sequence of numbers using this simple formula
nextNumber = (a * x + b) % m
Now comes the interesting part (which makes this work for your problem):
The Hull-Dobell-Theorem states that if your parameters a, b and m fit the following set of rules, the generator will generate every number between 0 and m-1 exactly once before repeating.
The conditions are:
m and the offset c are relatively prime
a - 1 is divisible by all prime factors of m
a - 1 is divisible by 4 if m is divisible by 4
This way you could generate your poems with exactly the same line of code as you currently have but instead just generate the array index with the LCG instead of rand.nextInt. This also means that this solution will give you the best performance, since there is no sorting, shuffling or searching involved.
Thanks for the responses everyone! This helped immeasurably. I am now officially traumatized by the sheer number of ways there are to solve even a simple problem.

Display the generated equation

I'm working on a school project in Android Studio and I've already asked here how to randomly generate equations, like 10+48*4. Someone suggested me this code to generate the equations:
String[] operationSet = new String[]{"+", "-", "/", "*"};
public void testGenerateRandomEquations() {
Random random = new Random();
int numOfOperations = random.nextInt(2) + 1;
List<String> operations = new ArrayList<>();
for (int i = 0; i < numOfOperations; i++) {
String operation = operationSet[random.nextInt(3)];
operations.add(operation);
}
int numOfNumbers = numOfOperations + 1;
List<Integer> numbers = new ArrayList<>();
for (int i = 0; i < numOfNumbers; i++) {
int number = random.nextInt(Integer.MAX_VALUE) - random.nextInt(Integer.MAX_VALUE);
numbers.add(number);
}
//Now you've the list of random numbers and operations. You can further randomize
//by randomly choosing the number and operation from those list.
}
But now I don't know how to display the generated equation. How can I display the equation for example in a TextView?
Maybe I'm just too dumb to understand but it would be nice if someone could help me :)
Here is the link to the original post: http://stackoverflow.com/a/39960279/6949270
All you have to do is to loop over the two lists - numbers and operations and concatenate them into a single string:
String equation = null;
for (int i = 0; i < numOfOperatrions; i++) {
equation += numbers.get(i);
equation += operations.get(i);
}
equation += numbers.get(numbers.size() -1); //Add the last number to the equation
The last line is needed because there are more numbers (one more) than operations.
It is better to use StringBuilder than String when concatenating strings, but for short strings it's OK.
EDIT - Why does it work?
We are concatenating String with an Integer, using the + operator.
The JAVA compiler converts in this case the Integer into a String, so no other casting is required.

How to find first instance of element array

I'm a pretty basic programmer and I'm coding a 'Master-mind' style guessing game program.
Now the part I'm stuck with is that I want to go through an array and increase the pointer when I come across a specific number.
Now thats pretty easy and stuff, but what I want to do is ONLY increase the counter if the number is encountered for the first time. So, for example if there are two numbers (189, 999), I want the counter to increase only once, instead of 3 times, which is what my code is doing. I know why its doing that, but I can't really figure out a way to NOT do it (except maybe declaring an array and putting all the repeated numbers in there and only incrementing it if none of the numbers match, but that's super inefficient) Here's my code:
for (int i = 0; i < mString.length(); i++) {
for (int j = 0; j < nString.length(); j++) {
if (mString.charAt(i) == nString.charAt(j)) {
correctNumbers++;
}
}
}
Thanks for taking the time to read! I'd prefer it if you wouldn't give me a direct answer and just point me in the right direction so I can learn better. Thanks again!
Your question is quite unclear. I suppose 989 and 999 will return 1. Because you only deal with number, so the solution is:
Create a boolean array with 9 element, from 0-9, named isChecked
Initialize it with false.
Whenever you found a matching number, say 9, turn the boolean element to true, so that you don't count it again (isChecked[9] = true).
Here is the code:
var isChecked = [];
function resetArray(input) {
for (var i = 0; i < 10; i++) {
input[i + ''] = false;
}
}
resetArray(isChecked);
var firstNumber = '989',
secondNumber = '999',
correctNumbers = 0,
fNum, sNum;
for (var i = 0; i < firstNumber.length; i++) {
fNum = firstNumber.charAt(i);
// Skip already checked numbers
if (isChecked[fNum]) {
continue;
}
for (var j = 0; j < secondNumber.length; j++) {
sNum = secondNumber.charAt(j);
if (fNum == sNum && !isChecked[sNum]) {
correctNumbers++;
isChecked[sNum] = true;
}
}
}
console.log(correctNumbers);
Tested on JSFiddle.
If you find anything unclear, feel free to ask me :)
(except maybe declaring an array and putting all the repeated numbers in there and only incrementing it if none of the numbers match, but that's super inefficient)
That approach is a good one, and can be made efficient by using a HashSet of Integers. Everytime you encounter a common digit, you do a contains on the set to check for that digit (gets in HashSets are of constant-time complexitiy - O(1), i.e. super quick), and if it's present in there already, you skip it. If not, you add it into the set, and increment your correctNumbers.
I believe this would help
int found=0; for (int i = 0; i < mString.length(); i++) {
for (int j = 0; j < nString.length(); j++) {
if (mString.charAt(i) == nString.charAt(j)) {
if(found==0){
correctNumbers++;
}
}
}
}
You could try making another 1D array of
int size = nstring.length() * mstring.length();
bool[] array = new bool[size];`
and then have that store a boolean flag of whether that cell has been updated before.
you would find the unique index of the cell by using
bool flag = false
flag = array[(i % mString.length()) + j)];
if(flag == true){
<don't increment>
}else{
<increment>
array[(i % mString.length()) + j)] = true;
}
you could also do this using a 2d array that basically would act as a mirror of your existing table:
bool[][] array = new bool[mstring.length()][nString.length()];
Why not just use the new stream api? Then it's just that:
Arrays.stream(mString).flatMapToInt(s -> s.chars()).distinct().count();
I'll explain:
Arrays.stream(mString) -> Create stream of all strings.
flatMapToInt -> create single concatenated stream from many IntStreams
s -> s.chars() -> Used above to create streams of characters (as ints)
distinct -> remove all duplicates, so each character is counted only once
count -> count the (unique) characters

List of Non-Repeating Ints in Java? Assignment

I'm trying to create a list of 20 integers between 0 and 26 (so in the 1-25 range) that does not repeat as a part of an assignment. I thought I had it figured out, but the program keeps looping over and over without ever ending. Can anyone help me out?
import java.util.Random;
public class prog433a
{
public static void main(String args[])
{
Random r = new Random();
int[] list = new int[20];
for (int k = 0; k < list.length; k++)
{
boolean notADupe = false;
while (notADupe == false)
{
list[k] = r.nextInt(25) + 1;
for (int j = 0; j < list.length; j++)
{
if (list[j] == list [k] && j != k)
{
notADupe = true;
}
else
{
notADupe = false;
break;
}
}
System.out.println(list[k]);
}
}
}
}
EDIT: This is different from the other question because I am trying to figure out how to check for uniqueness using the methods that I am allowed to use in my assignment (essentially, the ones I'm already using in the code).
I think you've reversed the condition out there. Inside if, you should set notADup to false, rather than true. However, I would make the variable isDup instead, and change the while loop accordingly.
One more suggestion: instead of while (notADupe == false), you should just use while (!notADupe). Never compare boolean variables like that. It might surprise you at times.
So to solve your issue, just change your if-else block to:
if (list[j] == list [k] && j != k) {
notADupe = false;
break;
} else {
notADupe = true;
}
BTW, your solution is a bit complex. For every element, you are iterating over whole array to find duplicate. Rather I would suggest you to maintain a Set<Integer> storing the already seen numbers, and check in that every randomly generated number. If present, skip it and re-generate.
Pseudo code would look something like this:
arr = [] // Your list array, initialize to size 20
seen = [] // A Set
for i from 1 -> arr.length
num = rand.nextInt(25) + 1
while seen contains num
num = rand.nextInt(25) + 1
seen.add(num)
arr[i] = num

Preventing Duplicate Integers in Array

I'm making an program for class that calls for the program to create 6 randomly generated integers in the range 1-40 and put them into an array. The integers have to be unique so there can't be a situation where a number certain number repeats. The array is then passed onto another method that sorts the array in ascending order. My problem is that I can't get my code to generate 6 unique numbers. My code is as follows:
private static void getComputer(int computerNumbers, int[] cN)
{
Random randomNumbers = new Random();
for (int i = 0; i < computerNumbers;)
{
int computerStored = randomNumbers.nextInt(39)+1;
if (computerStored == cN[0] || computerStored == cN[1] || computerStored == cN[2] ||
computerStored == cN[3] || computerStored == cN[4] || computerStored == cN[5])
continue;
else
computerStored = cN[i];
i++;
}
}
The above block of code outputs an array of 0,0,0,0,0,0. I just can't find out why. Any help would be much appreciated. Thank you.
Just for clarification, I know how to do a basic randomgenerator.
private static void getComputer(int computerNumbers, int[] cN)
{
Random randomNumbers = new Random();
for (int i = 0; i < computerNumbers; i++)
cN[i] = randomNumbers.nextInt(39)+1;
}
You probably meant
cN[i] = computerStored;
Note also that there are three issues with this code: You're passing in the size of the array, which is bad form in Java, you can never get zero (which is technically not a bug in this case since you're dealing with just 1-40), and your conditional is really unwieldy. Instead, I'd do this:
for(int i = 0; i < cN.length;) {
int candidate = randomNumbers.nextInt(39) + 1;
// actually, I'd either move this into another method or use a `Set` in the first place
boolean duplicate = false;
for(int j = 0; j < i || !duplicate; j++)
if(candidate == cN[j])
duplicate = true;
if(!duplicate)
cN[i++] = candidate;
}
I would approach this in a different way:
create a list of integers 1-40
shuffle them
create an array from the first 6 elements
Like this:
List<Integer> list = new ArrayList<>(40);
for (int i = 1; i < 41; i++)
list.add(i);
Collections.shuffle(list);
int[] cN = new int[6];
for (int i = 0; i < cN.length; i++)
cN[i] = list.get(i);
The advantage of this approach is you don't have to deal with the issue of duplicates, and it makes use of the JDK to do the randomizing.

Categories

Resources