Randomly selecting a unique element in a 2D Array - java

Hi so I'm doing an assignment but I've kind of fallen flat on the concept of 2D arrays. I'm writing a method body that randomly selects an element in a 2D array. However, I'm not completely sure when of how to approach the problem.
I was thinking of using a random number generator to select a random element. Although what I need first is for the whole length of the box to be filled first with a value. In this case, the dimensions of the 2D array box are 20x20 and the value is zero. So I'd want the 2D array to be complete filled with zeroes. Although if I used a random number generator, is there a chance that an element which was randomly selected by the generator could possibly be used again before the entire box dimensions are filled first with zero?
Sorry for the long block of text. Basically what I'm asking is if there is a way to use random number generator to still randomly generate numbers but not repeat any its used previously.

One option is to use Collections.shuffle(allCells).
Another option is to use the following algorithm, by keeping track of remaining unused cells:
1. Find a random number from 0 to size of the set - 1 .
2. Remove number at position `randomNumber` from the set.
3. Go to 1.

I would go this way:
int [][] myArray = new int[4][5]; //Any size and type
int totalEmenent = myArray.length *myArray[0].length;
int indexToSelect = (int)(Math.random()*totalEmenent);
int xIndex = (int)indexToSelect/myArray.length;
int yIndex = indexToSelect%myArray.length;
int selectElement = myArray[xIndex][yIndex];
If you wish to select unique index each time:
int [][] myArray = new int[4][5]; //Any size and type
int totalEmenent = myArray.length *myArray[0].length;
String selectedIndex = "";
int numberOfSelect = 10; //Any number< totalEmenent
for(int indx=0; indx< numberOfSelect; indx++){
int indexToSelect = (int)(Math.random()*totalEmenent);
//generate random until its unique
while(selectedIndex.indexOf(String.valueOf(indexToSelect))> 0){
indexToSelect = (int)(Math.random()*totalEmenent);
}
selectedIndex = selectedIndex+indexToSelect;
int xIndex = (int)indexToSelect/myArray.length;
int yIndex = indexToSelect%myArray.length;
int selectElement = myArray[xIndex][yIndex];
}

From what I read above... you want to fill a 20x20 2D array with 0's, but you want to do it by selecting a random location in the array each time, and you don't want to "re-fill" a slot.
The fastest way to do this is to create an array with all the possible locations (in this case, that's 0..399, if you figure that the value/20 = the first index, and value%20 = the 2nd index, e.g. 125 = array[125/20][125%20] or array[6][5], see?)
so, first, fill this array locations[400] with the values 0..399.
int [][] box = new int[20][20];
int [] locations = new int[400];
for ( int i = 0; i < 400; i++ ) locations[i] = i;
Then, starting with a cap of 399, generate a random number loc from 0 to cap, and use the locations[loc] as your current index to fill with a 0, then swap the locations[loc] with locations[cap], decrease cap by 1, and continue. By the time cap reaches 0, you'll have used all the locations.
int cap = 399;
Random rand = new Random();
while ( cap >= 0 ) {
int rnd = rand.nextInt(cap+1);
int loc = locations[ rnd ];
box[loc%20][loc/20] = 0; // Here's where we set the value 0 into the 2D array
// now swap the location selected with the value at the "end" of the current list.
// hmm, forget the swapping, let's just bring that value in from the end.
locations[rnd] = locations[cap];
cap--; // "shrink" the current list, eliminating the value we just put at the end from consideration.
}
That should do it. You should be able to see that this will never pick the same value out of the "locations" array, since the swap at the end of the loop puts that locations value outside the boundary of index 0 to cap. The next time through the loop, it's impossible to select that value again (or any other value that's already used).

While populating your array, you can have an arraylist to add the index of each cell(say i,j), and then generate random number
Arraylist<int[]> ar=new Arraylist();
//inside loop for populating array
yourArray[i][j]=whatever;
ar.add({i,j});
//loop ends
int index=new Random().nextInt(ar.size());
int[] arrayIndex=ar.get(index);
ar.remove(index);
row=arrayIndex[0];
column=arrayIndex[1];
(Type)randomElement=yourArray[row][column];

Related

How can I put a certain amount of integers in random locations in a 2d array?

I'm trying to put a certain amount of integers into an array in random spots without putting them in the same place.
My combine method concatenates two given integers and returns the Int.
Places is an arrayList to keep the locations of the integers already put into the array.
The random method returns a random integer in between the two given ints.
The combine method works and so does the random method, but I'm not sure why it isn't working.
public void fillOne(int b)
{
for(int x = 0; x < b; x++)
{
int kachow = random(0, 5);
int kachigga = random(0, 5);
int skrrt = combine(kachow, kachigga);
if(notInArray(skrrt))
{
locations[kachow][kachigga] = 1;
places.add(skrrt);
}
}
}
You haven't really explained what isn't working. But an obvious flaw in your algorithm is that it isn't guaranteed to set b elements to 1. If your algorithm generates a duplicate position then it will set fewer than b elements.
Your logic for storing the combined positions is overly complex. One solution would be to reverse the logic: generate a single integer representing both dimensions then divide it into two when you are setting the location. That makes the checks a lot simpler.
For example, if your array is 5x5:
Set<Integer> positions = new HashSet<>();
while (positions.size() < n)
positions.add(random.nextInt(25));
for (int p: positions)
locations[p/5][p%5] = 1;
Because positions is a set it automatically excludes duplicates which means the code will keep adding random positions until their are n distinct positions in the set.
Even simpler, if you are using Java 8:
random.ints(0, 25)
.distinct().limit(n)
.forEach(p -> locations[p/5][p%5] = 1);

Java Code More Efficient

I am creating a code here but I believe there is a way making the following more efficient. I tried many ways but it does not seem to work.
protected void randomise() {
int[] copy = new int[array().length]; //This makes the new int called randomIndex
// used to indicate if elements have been used
boolean[] used = new boolean[array().length]; //calling "used" as a new boolean for the array
Arrays.fill(used,false);
/**
* if index = 0, it means their is nothing in the index.
* if you apply a random number, it will copy that number to an array called index.
* if randomIndex in use, then the boolean becomes true.
*/
for (int index = 0; index < array().length;) {
do {
randomIndex = randomIndex();
} while (used[randomIndex]); //when random is in use, do the follow instruction.
copy[index] = array[index]; //copy the value value to an array called index.
used[randomIndex] = true; //when randomIndex is in use, then it becomes true.
}
//Of course, if there an extra random stores in the array, the index list is increased by one (index++).
for (int index =0;index < array().length; index++) {
array()[index] = copy[index]; //This tells where to copy the index value. in this case, it is a index array.
}
Do you have to use randomIndex?
If not you can use your bool[] to eliminate that do {} while() by sequentially adding the value to copy (which isn't a great name) and choosing a randInt in the range of the len of elements that haven't been selected, then using that bool[] to count a walk through the array elements ( to make your choice for the next element in copy.
You seem to want to randomly re-order an array. If so, then indeed there is a much more efficient solution. You are currently keeping two extra arrays on the size of the input (O(n)) while you do not have to.
The random shuffling is a common problem, and obviously there have been proposed several algorithms to accomplish this task. One of the most efficient algorithms is Knuth's algorithm for random permutation
The algorithms idea is, loop over the array once, and for each number i, perform a random exchange between i and a (random) array index between 0 and i. This guarantees that the array with be shuffled (meaning that each item will have equal possibility to be placed in each of the array indexes), in O(n) time and without using any extra space.
In short,
for (int i = 0; i < index; i++) {
int r = random.nextInt(i + 1);
exchange(array, i, r);
}
It is simple - use some collection of indexes and remove element when you used it. This way should looks like:
List<Integer> indexes = new ArrayList<>(array.length);
for (int i = 0 ; i < array.length ; i++) {
indexes.add(i);
}
Random r = new Random();
while (indexes.size() > 0) {
int randomIndex = r.nextInt(indexes.size());
int index = indexes.remove(randomIndex);
copy[index] = array[index];
}
Please note that:
you should check what is exact collection will be more efficient in your situation
Another way - create list values for array and use Collections.shuffle method on this list.
Additional another way - use some recursive algorithm to do that work.

How to generate a random number in java with array bounds?

I want to ask how to generate a random number in java , i know it is done by random.nextint() but i want to check if the number is not what i wanted then it should be rejected and a new random number should be generated .
I want something like this :
Integer[] in = {1,2,3,4,5};
int a = new Random().nextInt(10);
for(int i=0;i<in.length ;i++)
if(a==in[i])
//new random number
if the number is present in the above array (in) then new random number should be generated
Just put it in a do-while loop:
int a;
do {
a = new Random().nextInt(10);
} while (Arrays.asList(in).contains(a));
I would avoid not generating a number you didn't want in the first place.
You can do either
int a = random.nextInt(5);
if (a > 0) a += 5;
or use a selection
int[] valid = { 0, 6, 7, 8, 9 }; // 0 to 9 but not 1,2,3,4,5
int a = valid[random.nextInt(valid.length)];
Simply call the method again. That is, if the number generated fits the if criteria then call a = new Random().nextInt(10);
Or, if your for loop ever regenerates a random number, you could just have the if statement do nothing ex: if(xyz){}; which of course would be pointless, and I think the original solution is probably what you seek.
To avoid any loops and retrying, try this:
int [] in = {1,2,3,4,5};
// generate integers from 0 up to the size of your array of allowed numbers:
int index = new Random().nextInt(in.length);
int a = in[index]; // use the random integer as index for your array of allowed numbers

How can I sort an amount of randomly generated numbers defined by the user in Java?

Hey there Stack Overflow community, so I'm still new to Java but I am trying to learn how to sort. Right now my program creates n amount of random numbers from a range of 1 - 10. Although how I would go about putting these numbers into an array to be sorted, I'm not too sure on. Should i go about doing a bubble sort instead of Arrays.sort?
Here's my code
public static final void main(String aArgs){
//User inputs a number for the amount of random numbers to generate
String UserNumbers = JOptionPane.showInputDialog("How many numbers would you like to generate?");
//The unknown amount of numbers "n" is converted from the "UserNumbers" String to an int
int n = Integer.parseInt(UserNumbers);
//Random number generator generating the amount of numbers as defined by the user
Random randomGenerator = new Random();
for (int idx = 1; idx <= n; ++idx){
int randomInts = randomGenerator.nextInt(10);
//Now to create an array for the random numbers to be put into so they can be sorted
int ArrayToSort[] = new int[n];
ArrayToSort[0] = randomInts;
Arrays.sort(ArrayToSort);
System.out.println(ArrayToSort);
}
}
}
I suspect you are not asking whether to use bubble sort because it's faster/slower then Arrays.sort but instead as Arrays.sort doesn't work for you.
I think this is due to the fact your not putting the random numbers you generated into the array you sort
Instead, try this code:
public static final void main(String args){
//User inputs a number for the amount of random numbers to generate
String userNumbers = JOptionPane.showInputDialog("How many numbers would you like to generate?");
//The unknown amount of numbers "n" is converted from the "userNumbers" String to an int
int n = Integer.parseInt(userNumbers);
//Random number generator generating the amount of numbers as defined by the user
int arrayToSort[] = new int[n];
Random randomGenerator = new Random();
for (int idx = 0; idx < n; ++idx){
arrayToSort[idx] = randomGenerator.nextInt(10);
}
Arrays.sort(arrayToSort);
System.out.println(arrayToSort);
}
The problem with your code is that you are trying to populate an array of size n with random numbers, sort it and then print it, but your code generates in each iteration a random number, allocated an n sized array, put's the random number in slot 0 of the array and sort it, and print it (doint this n times) - which won't get the same effect ofcourse
BTW, Random.nextInt(10) return a random number between 0 and 9, not 1 and 10. to achieve what you want you will need to add 1 to that random value
Arrays.java 's sort method uses quicksort for arrays of primitives and merge sort for arrays of objects. I believe that most of time quicksort is faster than merge sort and costs less memory.
Source: Why does Java's Arrays.sort method use two different sorting algorithms for different types?

Array List Index 0 size 0 error

I'm making a program of the Card game War and I need the cards to not reappear so I used an Array list. I'm having trouble with this array list as it's supposed to be random and remove the number, but I get the error IndexOutOfBoundsException: Index 0, Size 0
List<Integer> values = new ArrayList<Integer>();
Random random = new Random();
Integer rand = random.nextInt(values.size()+1);
Integer cardId = values.get(rand);
values.remove(rand);
First add your Card(s) to your values List (e.g. probably not Integer).
What I'm saying is this, you need a deck of cards before you can play.
Your list is empty and you're
1) Trying to retrieve a value
2) Trying to remove a value
Which throws an error because the list is empty.
Sidenote: you can define rand and cardId as int, instead of Integer. Autoboxing/unboxing will take care of that for you.
Add values to your list and it will work as expected (and if you change random.nextInt(values.size()+1) to random.nextInt(values.size())).
You get this error because you try to access index 0 of an empty array, as it says. You cannot do this.
Your code has multiple issues.
You are not actually storing anything in values.
The acceptable range of indexes for .get() is 0 to size-1. The return range of random.nextInt(size+1) is 0 to size. This can produce out of range index values. Array indexes start at 0.
Provide the code for the values in the array...Or add values in the array.
You need to first give the List values before you can get values
List<Integer> values = new ArrayList<Integer>();
Random random = new Random();
Integer rand = random.nextInt(values.size()+1);
Try this to put values
for (int i = 1; i <= 52; i++){
values.add(i);
}
Integer rand = random.nextInt(values.size() + 1);

Categories