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]
Related
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) { ... }.
This question already has answers here:
Creating random numbers with no duplicates
(20 answers)
Closed 8 years ago.
Hello i have been working on insertion sort on set of numbers. i am able to add them to the array for performing the sorting but i was not able to generate unique values with large set of numbers to performing sorting(i:e)for 1000 values .is there any possibility i can generate unique random numbers for performing the sorting without adding values to the array?
public class InsertionBinary
{
public static void main(String Args [])
{
int[] nums = {1, 2, 3, 4, 5, 6, 7, 8, 24};
print(nums);
insertionsort(nums);
print(nums);
int loc = binarySearch(nums, 3);
System.out.println("2 is in position" + loc);
}
private static void swap(int[] list, int from, int to)
{
int temp = list[from];
list[from] = list[to];
list[to] = temp;
}
private static void print(int[] list)
{
for (int i = 0; i < list.length - 1; i++)
System.out.
print(list[i] + ", ");
System.out.println(list[list.length - 1]);
}
private static void insertionsort(int[] list)
{
int key;
int spot;
for (int pass = 1; pass < list.length; pass++)
{
key = list[pass];
for (spot = pass - 1; spot >= 0 && list[spot] > key; spot--)
list[spot + 1] = list[spot];
list[spot + 1] = key;
}
}
}
If all you want is a set of unique numbers for sorting, I would say the easiest approach would be to generate an array of size N containing the numbers 0 though N-1 (or 1 through N if you prefer) using a loop:
int size = 1000;
int[] nums = new int[size];
for(int i = 0; i < size; i++) {
nums[i] = i;
}
Then all you need to do is shuffle it, which you can do using your already-implemented swap() method and this helpful answer:
Random shuffling of an array
This has the advantage that it will run in O(n) time (instead of potentially infinite time if you're picking random numbers and then only inserting them if they're not already there).
Edit: You could also use Java's built-in shuffle method https://docs.oracle.com/javase/6/docs/api/java/util/Collections.html#shuffle(java.util.List)
you can use Math.random() and also add one condition that will check, array contains that number or not, if not contains then add otherwise don't add.
One simple solution is using Set generate your random numbers and insert them in a Set, set wont allow duplicate numbers, something like this :
Random rnd= new Random();
Set<Integer> randomSet = new LinkedHashSet<Integer>();
while (randomSet.size() < 1000)
{
Integer randomNum = rnd.nextInt(max) + 1;
randomSet.add(randomNum);
}
but it may take infinite time to generate a set like this in theory, but its probability is very low.
What Im trying to do is take my array coins[]. And basically rearrange each coin to a different position. This is what i have so far. When I do this though, nothing happens. Meaning all the values stay the same. Except for the last one. That one changes.
public void shake()
{
for (int i = 0; i < coins.length; i++)
{
int index = Coin.RANDOM.nextInt(coins.length);
Coin temp = coins[index];
coins[index] = coins[i];
coins[i] = temp;
System.out.print(coins[i] + ", ");
}
}
I instantiate random like this:
public static long SEED = System.currentTimeMillis();
public static Random RANDOM = new Random(SEED);
Please notice that this line
System.out.print(coins[swap] + ", ");
displays the already moved (swapped) coin. Maybe you were thinking about displaying the new coin at i index: coins[i] (which wouldn't be correct anyway, as the already displayed coin still can be swapped in the next iterations). Probably it's better to create a second for loop to display final coin values.
But this isn't only problem here. To randomly shuffle an array you should use Fisher-Yates algorithm which is slightly different than your method. You can find Java implementation of this algorithm on SO.
If you had a List<Coin> instead of Coin[] (list instead of array) you could use the Collections.shuffle method and be sure that the algorithm is correct and you'll always get random result.
As you are using swap as index with which you will be swapping the current value you can edit your Random number generator to generate random numbers between certain range (say 0 - coins.length) and then you can change your implementation to something like this
public void shake()
{
Coin temp;
for (int i = 0; i < coins.length; i++)
{
//int swap = Coin.RANDOM.nextInt(coins.length);
temp = coins[swap];
coins[swap] = coins[i];
coins[i] = temp;
System.out.print(coins[i] + ", ");
}
}
For the commented line in your code check THIS to update your random number generator to generate numbers between two values. Then each time you generate swap(index) between i+1 - coins.length and continue this till you fully exhaust the array. This ensures that you don't make a swap at the index the value for which you have already displayed. But I am not completely confident that this would indeed be a random shuffle as in the beginning of the loop you have more choices for the swap index then you would have sometime later in the loop and the shake is not completely random. This solution is only in case you want to strictly implement your own shake method without using the Collections.shuffle as #Tomek mentioned.
why don't you using Collections? its so simple to assign random indexes to each value in array or ArrayList.
Collections.shuffle(coins);//if coins is array
Collections.shuffle(Arrays.asList(coins));//if coins is an ArrayList
You might use Knuth's shuffling algorithm which rearranges the array so that a result is a uniformly random permutation. Algorithm is simple but works like a charm:
Iterate over array and in iteration i pick random integer swap between 0 and i
Swap array[i] and array[swap]
Note that in your implementation random is generated between 0 and 11, which doesn't seem to produce good shuffling.
Here is a code example with shuffling for array of integers:
import java.util.Random;
public class Test {
public static long SEED = System.currentTimeMillis();
public static Random RANDOM = new Random(SEED);
public static void shuffle(int[] numbers)
{
for (int i = 0; i < numbers.length; i++)
{
int swap = RANDOM.nextInt(i + 1);
int temp = numbers[swap];
numbers[swap] = numbers[i];
numbers[i] = temp;
}
for (int i = 0; i < numbers.length; i++) {
System.out.print(numbers[i] + ", ");
}
}
public static void main(String[] args) {
shuffle(new int[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11});
}
}
Output for test run is:
5, 11, 6, 1, 3, 10, 9, 2, 4, 7, 8,
Use this method and pass your array in parameter
Collections.shuffle(arrayList);
This method return void so it will not give you a new list but as we know that array is passed as a reference type in Java so it will shuffle your array and save shuffled values in it. That's why you don't need any return type.
You can now use arraylist which is shuffled.
Sourse: https://stackoverflow.com/a/16112539/4291272
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]);
}
I'm trying to figure out how to modify the n greatest elements of an array without modifying their position. For example, suppose I have an array of ints {5, 2, 3, 4, 8, 9, 1, 3};
I want to add 1 to the two greatest elements, making the array {5, 2, 3, 4, 9, 10, 1, 3}.
All of the methods I can think of to go about doing this end up feeling clunky and unintuitive when I try to implement them, signaling to me that I'm not thinking about it correctly. For example, I could use a TreeMap with the values of the array as keys and their indices as values to find the greatest values, modify them, and then throw them back into the array, but then I would have have to implement my own Comparator to sort the TreeMap in reverse order(unless there's an easier way I'm not aware of?). I was also considering copying the contents of the array into a list, iterating through n times, each time finding the greatest element and its index, putting the modified greatest element back into the array at that index, removing the element from the list, and repeat, but that feels sloppy and inefficient to me.
Any suggestions as to how to approach this type of problem?
The simplest thing would be to scan your array, and store the indices of the n highest values. Increment the values of those elements.
This is going to be O(n) performance, and I don't think any fancier methods can beat that.
edit to add: you can sort the array in place in O(n) at best, in which case you can get the n highest values very quickly, but the requirement is to not change position of the elements, so you'd have to start with a copy of the array if you wanted to do that (or preserve ordering information so you could put everything back afterward).
You might be over engineering the solution to this problem: scan the array, from beginning to end, and mark the two largest elements. Return to the two greatest elements and add 1 to it. The solution shouldn't be longer than 10 lines.
Loop over the array and keep track of the indices and values of the two largest items
a. Initialize the tracker with -1 for an index and MIN_INT for a value or the first two values of the array
b. At each step of the loop compare the current value against the two tracker values and update if necessary
Increment the two items
Any algorithm you choose should be O(n) for this. Sorting and n passes are way overkill.
Find the nth largest element (call it K) using techniques here and here (can be done in linear time), then go through the array modifying all elements >= K.
i would do something like this
int[] indices = new int[2];
int[] maximas = new int[] { 0, 0 };
int[] data = new int[] { 3, 4, 5, 1, 9 };
for (int i = 0; i < 5; ++i)
{
if (data[i] > maximas[1])
{
maximas[0] = maximas[1];
maximas[1] = data[i];
indices[0] = indices[1];
indices[1] = i;
}
else if (data[i] > maximas[0])
{
maximas[0] = data[i];
indices[0] = i;
}
}
didn't test it, but I think it should work :)
I have tought a bit about this but I cannot achieve more than worstcase:
O( n + (m-n) * n ) : (m > n)
best case:
O(m) : (m <= n)
where m = number of values, n = number of greatest value to search
This is the implementation in C#, but you can easily adapt to java:
int n = 3;
List<int> values = new List<int> {1,1,1,8,7,6,5};
List<int> greatestIndexes = new List<int>();
for (int i = 0; i < values.Count; i++) {
if (greatestIndexes.Count < n)
{
greatestIndexes.Add(i);
}
else {
int minIndex = -1, minValue = int.MaxValue;
for (int j = 0; j < n; j++)
{
if (values[greatestIndexes[j]] < values[i]) {
if (minValue > values[greatestIndexes[j]])
{
minValue = values[greatestIndexes[j]];
minIndex = j;
}
}
}
if (minIndex != -1)
{
greatestIndexes.RemoveAt(minIndex);
greatestIndexes.Add(i);
}
}
}
foreach (var i in greatestIndexes) {
Console.WriteLine(values[i]);
}
Output:
8
7
6