I've some strange situation here and i thought that you may help me. I have an int array populated with numbers from 1 to 10. I want to generate random number from this array and save it to another int array. I used class Random to pick any number and since random throws 0 also i modify it like that ( so it throws numbers from 1 to 10 )
randNum = rand.nextInt(numbers.length-min+1)+min;
Following code makes sure that if it generates same random number, it skips it. Program is actually working and i'm getting in another array randomly positioned numbers from 1 to 10. That's what i wanted. But sometimes i'm missing one number from 1 - 10 AND iam Getting ZERO instead. Why??
int[] numbers = {1,2,3,4,5,6,7,8,9,10};
int[] usednum = new int[10];
Random rand = new Random();
int randNum;
int min = 1;
for (int x = 0; x<numbers.length; x++) {
for (int i = 0; i<usednum.length; i++) {
randNum = rand.nextInt(numbers.length-min+1) + min;
for (int f = 0; f<usednum.length; f++) {
if (usednum[f] == randNum) {
break;
} else if (usednum[f] == 0) {
usednum[x] = randNum;
}
}
}
}
for (int c = 0; c<usednum.length; c++) {
System.out.println(usednum[c]);
}
You're inner-most for loop only checks if the current random number is in the usednum[] array. And the for loop immediately outer of that only checks 10 times total. It gives up too quickly because it only tries 10 random numbers. If all 10 are already used, nothing will get stored in that slot of usednum[] (thus it will be 0), try adding a while loop around that and get rid of the extraneous outer-most for loop:
for(int i = 0; i<usednum.length; i++) {
while(usednum[i]==0) {
randNum = rand.nextInt(numbers.length-min+1)+min;
for(int f = 0; f<usednum.length; f++) {
if(usednum[f] == randNum) {
break;
} //if
else if (usednum[f] == 0) {
usednum[i] = randNum;
}
}
}
}
Also note that the assignment is for usednum[i] = randNum;.
This is essentially replacing the middle for loop (the one that goes from i=0 to 9) with the while loop.
If your goal is simply to shuffle an array of numbers, try this instead:
Integer[] numbers = {1,2,3,4,5,6,7,8,9,10};
Collections.shuffle(Arrays.asList(numbers));
It will have the same effect. Unless you are completing a homework assignment that forces you to solve the issue in a more manual fashion, just make use of the standard Java libraries.
The shuffle method writes changes through to the underlying Integer array, thanks to the special type of List returned by Arrays.asList(...). Note you have to use an array of Integer not int (see Why does Collections.shuffle() fail for my array?).
You are generating used numbers through an entire pass, so it doesn't generate a zero is just fails to generate a value it should.
you have one for loop too much.
remove the loop with the i iterator and the program should do what you want.
Oh and remove the -min+1 from the random generator, -1+1=0
Your array usednum is consisted of zeros at the beginning. In some cases, your program doesn't change that initial value, but breaks before at the line:
if(usednum[f] == randNum)
and does that during all iterations with same value x. X increments and there goes your chance to change the zero value.
Edit - followed it and re-wrote it:
List<Integer> numbers = new LinkedList<Integer>(Arrays.asList(new Integer[]{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }));
int[] usednum = new int[10];
Random rand = new Random();
int n = numbers.size();
for (int i = 0; i < n; i++) {
int randNum = rand.nextInt(numbers.size());
usednum[i]=numbers.get(randNum);
numbers.remove(randNum);
}
for (int c:usednum) {
System.out.println(c);
}
Actually, you are never using the content of the array numbers. Try changing the array to something like int[] numbers = { 10, 22, 23, 42, 53, 18, 7, 8, 93, 10 };. You will get similar output.
Jon Lin's answer describe why your code is not working but does not address this issue. I think you will want to change your code to something like:
int[] numbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int[] usednum = new int[10];
Random rand = new Random();
int selectedCount = 0;
while (selectedCount < numbers.length) {
int randNum = numbers[rand.nextInt(numbers.length)];
boolean contains = false;
for (int x = 0; x < selectedCount; x++) {
if (usednum[x] == randNum) {
contains = true;
break;
}
}
if (!contains) {
usednum[selectedCount] = randNum;
selectedCount++;
}
}
for (int c = 0; c < usednum.length; c++) {
System.out.println(usednum[c]);
}
Related
This question already has answers here:
Creating random numbers with no duplicates
(20 answers)
Closed 1 year ago.
This is probably already asked, but it is a little difficult for me to understand. I created a for loop to add random integers into my array, but when the integer is already in the array, restart the loop. But I keep on getting the same integers into the array + when there already is a duplicate, the array size increases. Does anyone know what I'm doing wrong?
Random r = new Random();
int[] tes = new int[5];
for (int i = 0; i < tes.length; i++) {
int q = r.nextInt(10);
for (int j = 0; j < i; j++) {
if (q == tes[j]){
i=i-1;
}
}
tes[i] = q;
System.out.println(tes[i]);
}
and the output:
If you want a collection without duplicates you should use a Set:
Random r = new Random();
int desirableSize = 5;
Set<Integer> uniques = new HashSet<>(desirableSize);
while(uniques.size() < desirableSize){
uniques.add(r.nextInt(10));
}
System.out.println(uniques);
The add method already ensures that a value is not added if it already exist on the set.
boolean add(E e)
Adds the specified element to this set if it is not already present (optional operation).
I have used HashSet, however if the insertion order is important for you, use instead LinkedHashSet:
As pjs have pointed out the aforementioned approach is good when:
desirableSize is much less than the pool size, but if the
desirableSize is a substantial proportion of pool size you're better
off shuffling the pool and selecting the first desirableSize elements.
Something as follows:
int start = 0;
int end = 10;
int size = 5;
List<Integer> collect = IntStream.rangeClosed(start, end)
.boxed()
.limit(size)
.collect(Collectors.toList());
Collections.shuffle(collect);
System.out.println(collect);
The rational is the following (quoting pjs):
With rejection-based schemes such as repeated attempts to add to a
set, the expected number of iterations is O(poolsize *
log(desirableSize)) with O(desirableSize) storage for the set.
Shuffling is O(poolsize) but requires O(poolsize) storage for the
shuffle. As desirableSize -> poolsize, shuffling wins on expected
iterations and becomes competitive on storage. With partial shuffling
implementations, the number of iterations for shuffling is
O(desirableSize) although the storage remains the same.
Or more informally, the higher it is the unique finite set of numbers that will be pickup from a finite set of possible numbers, the more desirable it is to use the second approach.
For instance, if one generates numbers from 0 to 1000 and is only interested in 5 numbers, since the probability of picking randomly the same numbers is lower, one is better off with the first approach. However, if you would be (instead) interested in 800 numbers, then one would be better off generating and shuffling the 1000 numbers, and extracting the 800 unique values from them.
Memory-wise the first approach is better then second approach, however performance-wise it depends in the context as we have already described.
i dont see a problem.
Your System.out.println(tes[i]); is in loop
your array has only following ints: 5,9,2,7,1
make println in own loop
for (int i = 0; i < tes.length; i++) {
System.out.println(tes[i]);
}
because you make i=i-1; one value is printed many times
I managed to solve it in a different way:
List<Integer> tes = new ArrayList<>(5);
Random r = new Random();
for (int i = 0; i < 5; i++) {
int testNummer = r.nextInt(10);
if(!tes.contains(testNummer)) {
tes.add(testNummer);
System.out.println(testNummer);
}else{
i=i-1;
}
}
this way is more efficient, I have noticed.
Some logic problem
Increment i variable when you store value in array and don't decrement i variable just break inner loop when found duplicate.
when duplicate found then restart outer loop. use if else condition for that
try below code and for simple understanding i have changed outer loop in while
int i = 0;
while(i<5)
{
int q = r.nextInt(10);
System.out.println("random value generated"+ q );
int j=0;
for (;j < i; j++)
{
if (q == tes[j])
{
System.out.println("duplicate value found"+ q );
break;
}
}
if(j!=i)
{
continue;
}
else
{
if(j==i)
{
tes[i] = q;
i=i+1;
}
}
System.out.println("value at "+ tes[i]);
}
If you want an easy way to generate unique values you can do it with a stream.
Random r = new Random();
int minVal = 1;
int upperBound = 20;
int count = 10;
As long as count is less than upperBound - minVal it will finish without duplicates. For very large counts with the appropriate range, it may take some time.
int[] unique = r.ints(minVal, upperBound).distinct().limit(count).toArray();
System.out.println(Arrays.toString(unique));
Prints something like this.
[14, 1, 7, 13, 5, 16, 2, 8, 12, 4]
An easy way to generate random numbers of a fixed range is to simply shuffle the array.
Integer[] vals = new Integer[20];
for (int i = 0; i < vals.length; i++) {
vals[i] = i+1;
}
// Object array will be shuffle since it backs up the list.
Collections.shuffle(Arrays.asList(vals));
System.out.println(Arrays.toString(vals));
Prints something like
[7, 20, 5, 10, 17, 18, 3, 13, 11, 1, 2, 8, 4, 9, 19, 12, 15, 16, 6, 14]
For my assignment, I need to write a method that returns the number of cows (see definition below) found between 2 arrays. If the input arrays have a different number of elements, then the method should throw an IllegalArgumentException with an appropriate message.
A bull is a common number in int arrays found at the same position while a cow is a common number in int arrays found at different position. Note that if a number is already a bull, it cannot be considered as a cow.
For example, considering the following arrays:
int[] secret = {2, 0, 6, 9};
int[] guessOne = {9, 5, 6, 2};
int[] guessTwo = {2, 0, 6, 2};
int[] guessThree = {1, 2, 3, 4, 5, 6};
int[] guessFour = {1, 3, 4, 4, 0, 5};
1) getNumOfCows(secret, guessOne) returns 2
2) getNumOfCows(secret, guessTwo) returns 0
3) getNumOfCows(secret, guessThree) returns an exception
4) getNumOfCows(guessThree, guessFour) returns 2
My method seen below works perfectly for examples 1 and 3, but there is a problem with examples 2 and 4 such that getNumOfCows(secret, guessTwo) returns 1 instead of 0 because the element at secret[0] and guessTwo[3] is considered a cow. Could anybody help me fix my code?
// A method that gets the number of cows in a guess --- TO BE FIXED
public static int getNumOfCows(int[] secretNumber, int[] guessedNumber) {
// Initialize and declare a variable that acts as a counter
int numberOfCows = 0;
// Initialize and declare an array
int[] verified = new int[secretNumber.length];
if (guessedNumber.length == secretNumber.length) {
// Loop through all the elements of both arrays to see if there is any matching digit
for (int i = 0; i < guessedNumber.length; i++) {
// Check if the digits represent a bull
if (guessedNumber[i] == secretNumber[i]) {
verified[i] = 1;
}
}
for (int i = 0; i < guessedNumber.length; i++) {
// Continue to the next iteration if the digits represent a bull
if (verified[i] == 1) {
continue;
}
else {
for (int j = 0; j < secretNumber.length; j++) {
if (guessedNumber[i] == secretNumber[j] && i != j) {
// Update the variable
numberOfCows++;
verified[i] = 1;
}
}
}
}
}
else {
// Throw an IllegalArgumentException
throw new IllegalArgumentException ("Both array must contain the same number of elements");
}
return numberOfCows;
}
First go through and mark all bulls using a separate array to make sure a position that is a bull also get counted as a cow
public static int getNumOfCows(int[] secretNumber, int[] guessedNumber) {
int max = secretNumber.length;
int cows = 0;
int[] checked = new int[max];
for (int i = 0; i < max; i++) {
if (secretNumber[i] == guessedNumber[i]) {
checked[i] = 1;
}
}
for (int i = 0; i < max; i++) {
if (checked[i] == 1) {
continue;
}
for (int j = 0; j < max; j++) {
if (secretNumber[i] == guessedNumber[j]) {
cows++;
checked[i] = 1;
}
}
}
return cows;
}
Now that this answer is accepted the original question can be voted to be closed as a duplicate
I am posting my answer from a duplicate question here and if this get approved then the other one can get closed as a duplicate.
The problem is that an element that is multiple times in at least one array will not be handled correctly.
A possible solution idea might be this one:
Create a cow list.
Iterate through both arrays and add every element that is in both arrays and has not been added yet. (note: complexity is n²)
Now that all possible cows are in the list, iterate through the array positions with the same index and if you find a bull, remove the number from the cow list.
Now the cow list contains only cows.
This solution might be a bit slower than your current one, but I think it's working properly.
I want to generate two random pair of integer with no duplicate in an array of length 8 and I don't want any pair in the same diagonal
public static int[] randomizer(int[] v){
int [] a= new int[8];
for (int i = 0; i < a.length; i++) {
a[i] = (int)(Math.random()*9);
for (int j = 0; j < i; j++) {
if (a[i] == a[j]) {
i--;
break;
}
}
}
a[0] = v[0] ;
return a;
}
This is what I have done so far.
If I understood you correctly you want to generate two random sequences of integers with the length of 8 each. Both sequences should not have any number in common, so you want 16 unique random numbers.
Next comes the requirement with the diagonal part - I don't get it. Please specify it more precice, a small example would be nice.
Meanwhile let's solve the first part. Generating 16 unique integers is quite easy. You generate a random number and memorize it. If it was already generated before than reject it and try again. For a fast contains access and add you should use a HashSet. Let's take a look at the following snippet:
public static Set<Integer> randomUniqueNumbers(int amount, int upperBound){
final HashSet<Integer> numbers = new HashSet<>();
final Random rnd = new Random();
// Stop when generated enough numbers
while (numbers.size() < amount) {
final int randomNumber = rnd.nextInt(upperBound);
// Try to add it to the set.
// The method will do nothing if the number was contained already.
numbers.add(randomNumber);
}
return numbers;
}
The method will generate amount many unique numbers and store them in a Set<Integer> that can be iterated and used by your method. The numbers are between 0 (inclusive) and upperBound (exclusive) like with (int)(Math.random() * upperBound) you used.
Note that it is possible that the while-loop does not halt, for example when extremely unlucky or the given parameters contradict. If that is a problem you can count the number of unsuccessful tries and abort with break once it goes beyond a defined upper limit of tries.
You want 16 of those numbers and store them in two arrays of length 8 each. Here's is how you can do this:
final int[] firstSequence = new int[8];
final int[] secondSequence = new int[8];
// Exchange with the correct upperBound, I assume it is 9
final Set<Integer> numbers = randomUniqueNumbers(16, 9);
Iterator<Integer> numberIter = numbers.iterator();
// Fill the first sequence
for (int i = 0; i < 8; i++) {
firstSequence[i] = numberIter.next();
}
// Fill the second sequence
for (int i = 0; i < 8; i++) {
secondSequence[i] = numberIter.next();
}
I think that covers most of your question. Please specify more precise what is missing and I will update the answer.
Also note that randomUniqueNumbers(16, 9) can not halt. It will run forever since it is not possible to generate 16 different numbers out of {0, 1, 2, 3, 4, 5, 6, 7, 8} which are only 9 numbers. Also note that when both parameters are close it will be drastically faster to use another approach where you pre-define {0, 1, 2, 3, 4, 5, 6, 7, 8} and now just permutate this set and then iterate it, like Collections.shuffle(numbers) and then for(Integer number : numbers) { ... }.
I have to list out 10 unique numbers between 1 and 20, but before storing the numbers, the program should check whether the number is in the list or not. If the number is already in the list, it should generate a new number. Also, the amount of numbers replaced must be counted.
This is what I have so far:
public static void main(String[] args)
{
int[] arrayA = {16, 14, 20, 3, 6, 3, 9, 1, 11, 2};
System.out.print("List: ");
for(int w = 0; w < arrayA.length; w++)
{
System.out.print(arrayA[w] + " ");
}
}
As you can see, there are two "3"s on the list, I have to output the same list but change one of the "3"s. Plus it has to be counted.
This is not hard to do, but what do you mean by change one of the threes?
You can add a boolean flag outside of your for loop that can tell if you've encountered a 3 or not and what the index of that 3 is.
Try something like this:
boolean changedThree = false;
int threeIndex = -1;
for(int i = 0; i < arrayA.length; i++){
if(arrayA[i] == 3 && !changedThree){
arrayA[i] = 4;
threeIndex = i;
changedThree = true;
}
System.out.println(arrayA[i] + " ");
}
I don't know for sure if that captures the information you need, but hopefully can give you a push in the right direction. Let me know if you have questions.
EDIT
To avoid any duplicate values, I recommend you create an array list, and add the unique values to it. Then, you can use the ArrayList.contains() method to see if a value exists already. So, I would recommend changing your code to this:
ArrayList<int> usedCharacters = new ArrayList<int>();
int changedCounter = 0;
Random rand = new Random();
for(int i = 0; i < arrayA.length; i++){
if(!usedCharacters.contains(arrayA[i])){ // If we haven't used this number yet
usedCharacters.add(arrayA[i]);
} else{
// Generate a new number - make sure we aren't creating a duplicate
int temp = rand.nextInt(20) + 1;
while(usedCharacters.contains(temp)){
temp = rand.nextInt(20) + 1;
}
// Assign new variable, increment counter
arrayA[i] = temp;
changedCounter++;
}
}
If you're not familiar with the random.nextInt() method, read this.
so if I understand you correctly you have to save the arrayA, right?
If that is the case, you can just make a new array, targetArray where you can save to numbers to, and then check using a for-loop if you already added it, and if so you can generate a new, random number.
The result would look something like this:
public static void main(String[] args) {
int[] arrayA = {16, 14, 20, 3, 6, 3, 9, 1, 11, 2};
int[] targetArray = new int[10];
int numbersReplaced = 0;
System.out.print("List: ");
for (int i = 0; i < arrayA.length; i++) {
for (int j = 0; j < targetArray.length; j++) {
if (arrayA[i] == targetArray[j]) {
targetArray[j] = (int)(Math.random() * 100);
numbersReplaced++;
} else {
targetArray[j] = arrayA[i];
}
}
}
System.out.println("Numbers replaced: " + numbersReplaced);
}
Hope that helped
You could use recursion to achieve your result.
This will keep looping until all values are unique
private void removeDoubles(int[] arr) {
for(int i = 0; i < arr.length; i++)
{
// iterate over the same list
for(int j = 0; j < arr.length; j++) {
// Now if both indexes are different, but the values are the same, you generate a new random and repeat the process
if(j != i && arr[i] == arr[j]) {
// Generate new random
arr[j] = random.nextInt(20);
// Repeat
removeDoubles(arr);
}
}
}
}
Note: This is the sort of question I prefer to give guidance answers rather than just paste in code.
You could walk the array backward looking at the preceding sublist. If it contain the current number you replace with a new one.
Get the sublist with something like Arrays.asList(array).subList(0, i) and then use .contains().
You logic for finding what number to add depends on lots of stuff, but at it simplest, you might need to walk the array once first to find the "available" numbers--and store them in a new list. Pull a new number from that list each time you need to replace.
EDIT: As suggested in the comments you can make use of Java Set here as well. See the Set docs.
Can somebody PLEASE answer my specific question, I cannot use material not covered in class yet and must do it this way.
I'm trying to iterate over a sorted array and if the previous number == the current number it stores the count in possiton n of a new array; when the previous number != the current number, it then moves to n+1 on the new array and starts counting again.
I'm debugging it now but having trouble working out what it isn't work. Any help is much appreciated.
// Get the count of instances.
int[] countOfNumbers = new int[50]; // Array to store count
int sizeOfArray = 0; // Last position of array filled
int instanceCounter = 1; // Counts number of instances
int previousNumber = 0; // Number stored at [k-1]
for (int k=1; k < finalArrayOfNumbers.length; k++) {
previousNumber = finalArrayOfNumbers[k-0];
if (previousNumber == finalArrayOfNumbers[k]) {
instanceCounter++;
countOfNumbers[sizeOfArray] = instanceCounter;
}
instanceCounter = 1;
sizeOfArray++;
countOfNumbers[sizeOfArray] = instanceCounter;
Don't worry about mapping or anything, I just need to know how If I have an array of:
[20, 20, 40, 40, 50]
I can get back
[2, 2, 1]
There's lots of neat tools in the Java API so you can avoid doing a lot of this yourself:
List<Integer> list = Arrays.asList(20, 20, 40, 40, 50);
Map<Integer, Integer> freq = new LinkedHashMap<>();
for (int i: list) {
freq.put(i, Collections.frequency(list, i));
}
System.out.println(freq.values());
That'll print [2, 2, 1] like you wanted.
Alternatively if you'd like a list of only the distinct values in the list, you can use an implementation of Set.
But since you're restricted because this is a class assignment, you could do something like this instead:
int[] a = { 20, 20, 40, 40, 50 };
int[] freq = new int[a.length];
// count frequencies
for (int i = 1, j = 0, count = 1; i <= a.length; i++, count++) {
if (i == a.length || a[i] != a[i - 1]) {
freq[j++] = count;
count = 0;
}
}
// print
for (int i = 0; i < freq.length && freq[i] != 0; i++) {
System.out.println(freq[i]);
}
And the output is still the same.
I put comments in the two places you were off, here's your fixed code.
for (int k = 1; k < finalArrayOfNumbers.length; k++) {
previousNumber = finalArrayOfNumbers[k - 1]; // changed 0 to 1
if (previousNumber == finalArrayOfNumbers[k]) {
instanceCounter++;
countOfNumbers[sizeOfArray] = instanceCounter;
} else { // put this last bit in an else block
instanceCounter = 1;
sizeOfArray++;
countOfNumbers[sizeOfArray] = instanceCounter;
}
}
I'm debugging it now but having trouble working out what it isn't work. Any help is much appreciated.
Here's a clue for you:
previousNumber = finalArrayOfNumbers[k-0];
if (previousNumber == finalArrayOfNumbers[k]) {
Clue: 'k - 0' has the same value as 'k' in the above.
Clue 2: If your intention is that previousNumber contains the number you are currently counting, then it needs to be initialized outside of the loop, and updates when the current number changes.
Clue 3: You should not increment sizeOfArray on every loop iteration ...
Based on your Question, I'd say that your thinking about / understanding of the code that you have written is woolly. And this is why you are having difficulty debugging it.
In order to debug a piece of code effectively, you first need a mental model of how it ought to work. Then you use the debugger to watch what is happening at key points to confirm that the program is behaving as you expect it to.
(If you come into the debugging process without a mental model, all you see is statements executing, variables changing, etcetera ... with nothing to tell you if the right thing is happening. It is like watching the flashing lights on a computer in an old movie ... not enlightening.)
I would opt for a hashmap where the key is the number and its value the count. This way you have a unique number and count. Your solution runs into a problem where you don't really know at index i, what count that number belongs to, unless your list has no duplicates and is in order with no gaps, like 1, 2, 3, 4, 5 as opposed to the case of 1, 1, 1, 1, 5, 5, 5, 5
HashMap<Integer, Integer> occurances = new HashMap>Integer, Integer>();
int[] someSortedArray = new int[10];
//fill up a sorted array
for(int index = 0; index < someSortedArray.length; index++)
{
someSortedArray[index] = index+1;
}
int current = someSortedArray[0];
int count = 1;
for(int index = 1; index < someSortedArray.length; index++)
{
if(someSortedArray[index] != current)
{
occurances.put(current, count);
current = someSortedArray[index];
count = 1;
}else
{
count++;
}
}
System.out.println(occurances);
I think this should do it (haven't compiled).
You where not increasing sizeOfArray anywhere in your for loop.
// Get the count of instances.
int[] countOfNumbers = new int[50]; // Array to store count
int sizeOfArray = 0; // Last position of array filled
int instanceCounter = 1; // Counts number of instances
int previousNumber = finalArrayOfNumbers[0]; // Number stored at [k-1]
for (int k=1; k < finalArrayOfNumbers.length; k++) {
if (previousNumber == finalArrayOfNumbers[k]) {
instanceCounter++;
}
else
{
countOfNumbers[sizeOfArray] = instanceCounter;
instanceCounter = 1;
sizeOfArray++;
previousNumber = finalArrayOfNumbers[k]
}
}
countOfNumbers[sizeOfArray] = instanceCounter;