This question already has an answer here:
Pick random element from array, but unique
(1 answer)
Closed 9 years ago.
I'm trying to make an array of random colors from another array.
String [] colors = new String[6];
colors[0] = "red";
colors[1] = "green";
colors[2] = "blue";
colors[3] = "yellow";
colors[4] = "purple";
colors[5] = "orange";
That's my array as of now. I want to make a new array with just 4 of those colors without duplicates.
So far I know how to make an array of randoms; however, I don't know how to take care of duplicates efficiently.
Sounds like you want a Set. A Set is designed to remove duplicates.
Set<String> set = ...
for(String s : "a,b,c,d,e,f,d,e,c,a,b".split(","))
set.add(s);
This set will have all the unique strings.
List<String> colourList = new ArrayList<String>(Arrays.asList(colors));
Collections.shuffle(colourList);
return colourList.subList(0,4).toArray();
I'd strongly suggest you don't use arrays for this. Add what you need to a Set and it will handle duplicate management for you. You can always convert back to an array if need be.
You can just select random entries from colors, and add them into a Set until the set has four elements:
Set<String> randomStrings = new HashSet<String>();
Random random = new Random();
while( randomStrings.size() < 4) {
int index = random.nextInt( colors.length);
randomStrings.add( colors[index]);
}
You can try it out in this demo, where it selects four colors at random when you run it. You'll get output similar to:
Random colors: [orange, red, purple, blue]
Related
This is a peice of my code, i am making a grid of 5x5 with random colors set to each section. I need to set the specified y_loc and x_loc in the list to the color randomly picked except i have not been able to find out how. It should be the second last line that is not operating as id like. I understand that i could do this in much much longer code but it would be nice to do it in less.
//making the map
ArrayList<ArrayList<String>> fullmap = new ArrayList<ArrayList<String>>();
ArrayList<String> y_row_0 = new ArrayList<String>();
ArrayList<String> y_row_1 = new ArrayList<String>();
ArrayList<String> y_row_2 = new ArrayList<String>();
ArrayList<String> y_row_3 = new ArrayList<String>();
ArrayList<String> y_row_4 = new ArrayList<String>();
//adding each row
fullmap.add(y_row_0);
fullmap.add(y_row_1);
fullmap.add(y_row_2);
fullmap.add(y_row_3);
fullmap.add(y_row_4);
Random rn = new Random();
//loop to randomly pick colors then set them to their destined locations
for (int y_loc = 0; y_loc < 6; y_loc++){
for (int x_loc = 0; x_loc < 6; x_loc++){
colorPicked = false;
while (!colorPicked){
int ranNum = rn.nextInt();
if (ranNum ==0){
if (redTot < 5) {
redTot += 1;
fullmap.set(y_loc).set(x_loc, "Red"));
colorPicked = true;
Since you have lists in list here, to set something at a specific location, you'll have to get the inner list and then perform the set on it.
The following should work:
fullmap.get(y_loc).set(x_loc, "Red"));
Also, since you seem to always have a 5x5 matrix, I'd recommend using a double array instead. That'd make that line:
fullmap[x_loc][y_loc] = "Red";
You should have something like this:
fullmap.get(y_loc).set(x_loc, "Red"));
Notice the "get". You are "getting" the list at the y location, which returns an array list, then calling "set" against that array list to set the actual value in the index of the "x_loc" value.
You need to make a couple of changes:
While declaring the sub lists, you need to make sure they have 5 empty/null elements. Otherwise set will throw IndexOutOfBoundsException. E.g. you need to declare the lists like this:
ArrayList<String> y_row_0 = Arrays.asList(new String[5]);//Assuming it will have 5 elements
While setting the element, you first need to get the corresponding sub list, e.g. the following needs to be changed from:
fullmap.set(y_loc).set(x_loc, "Red"));
to
fullmap.get(y_loc).set(x_loc, "Red"));
Others have already discussed the indexing issue. Apart from that, I believe that your conditionals may not be executing as you expect. nextInt() will return a reasonable uniform random number in the range of -2147483648 to 2147483647. You have a 1/2^64 chance of getting a 0. Reduce the random number range to something more reasonable. For example, nextInt(10) will return a random number between 0 and 9.
Furthermore, if the probability is too low, you will not get 5 reds all the time. To guarantee 5 picks and for the sake of computational efficiency, it is better to randomly pick array indices and evaluate whether a color is set or not, such as the following pseudo-code
int redTot = 0;
while ( redTot < 5 ) {
int r = rn.nextInt( 5 );
int c = rn.nextInt( 5 );
String color = fullmap.get( r ).get( c );
if ( color == null ) {
fullmap.get( r ).set( c, "Red" );
redTot++;
}
}
Let's say I want to generate 20 random numbers on a 8 by 6 grid.(8 columns, 6 rows) . Based on the answer from here:Creating random numbers with no duplicates, I wrote my code like this:
Random randomNumGenerator = new Random();
Set<Integer[][]> generated = new LinkedHashSet<Integer[][]>();
while (generated.size() < 20) {
int randomRows = randomNumGenerator.nextInt(6);
int randomColumns = randomNumGenerator.nextInt(8);
generated.add(new Integer[][]{{randomRows,randomColumns}});
}
In reality what happens is the Set see Integer[][]{{5,5}}; and Integer[][]{{5,5}};as NOT duplicate.Why? Even tho my purpose is to get 20 non-duplicate pair of numbers, this does not work. How do I fix this?
The Set checks for duplicates using the equals method (and also the hashCode method) of its inner type, but the Integer[][]'s equals method compares the memory addresses and not the contents.
Why do you use a Set of Integer[][] if you just want to store pairs?
Unfortunately, in Java there is no Pair class, but if you do not want to create your own, you can use the Map.Entry for that.
Random randomNumGenerator = new Random();
Set<Map.Entry<Integer, Integer>> generated = new LinkedHashSet<>();
while (generated.size() < 20) {
int randomRows = randomNumGenerator.nextInt(6);
int randomColumns = randomNumGenerator.nextInt(8);
generated.add(new AbstractMap.SimpleEntry<>(randomRows,randomColumns));
}
System.out.println(generated);
Array equals is == in Java, so an array is only equal to itself. Normaly you use Arrays.equals(array1, array2) to compare them by content, but in this case, arrays are simply the wrong choice. You can either create a bean, as rafalopez79 suggested of use an array of Collections (List in your case), as a List will compare the content on equals, see the documentation. Choice is pretty much yours, a bean would probably be a bit cleaner.
How about this code. I ran it through the debugger, it works nicely and yes, the contains() method checks the value of the Integer, not the reference. You can change the range of the random number as needed, I used 5 to facilitate testing. Yes I know it's not very robust, as written this will be an endless loop (because of the limited range of 5) but it's a simple example to make the point.
UPDATE: Actually this has a bug in that it won't check for uniqueness across all the rows, but that's easily fixed as well. I just re-read the original question and looking at the original code I'm not sure I know what you want exactly. If you just want a grid with 48 unique Intergers arranged 8 by 6 this will do it, but there are several ways to do this.
final int rows = 6;
final int cols = 8;
Random randomGenerator = new Random();
ArrayList[] grid = new ArrayList[rows];
for(int i=0; i<rows; i++)
{
grid[i] = new ArrayList<Integer>();
for(int j=0; j<cols; j++)
{
for(;;)
{
Integer newInt = new Integer(randomGenerator.nextInt(5));
if(!grid[i].contains(newInt))
{
grid[i].add(newInt);
break;
}
}
}
}
Problem
I am building an app which can create raffle draws from an arrayList of entries. When starting the draw, the user can input an integer which states how many winners the draw will return. The app uses randomGenerator to pick a random index from the entry arrayList. This randomGenerator is within a for loop which checks how many times it has been iterated over and compares it to the numberOfWinners integer.
Say the user inserted "3" as their integer for numberOfWinners. The app would return three random entries, however there are sometimes duplicates.
So naturally I researched how to avoid duplicates. I came across HashSet. If two duplicate entries are added to the HashSet, only one unique entry is added. I then converted this HashSet into a new ArrayList, and displayed it on my Android view as a ListView.
However, the HashSet has not solved the problem. If the user enters the input "3" for numberOfWinners, and there is a duplicate, the end result will only be 2 entries.
How can I solve this problem?
Here is a segment of my code:
Set <Entry>drawSet = new HashSet<Entry>();
//Picks random int from size of entry arrayList
Intent viewDrawIntent = getIntent();
int currentRaffleID = viewDrawIntent.getIntExtra("raffleIndexInList", 0);
int newNoOfWinners = viewDrawIntent.getIntExtra("extraNoOfWinners", 0);
Raffle currentRaffle = Raffle.raffleArrayList.get(currentRaffleID);
for (int i = 1; i < (currentRaffle.getEntryArrayList().size()); i++) {
if(i != newNoOfWinners){
int randomInt = randomGenerator.nextInt(currentRaffle.getEntryArrayList().size());
Entry randomEntry = (currentRaffle.getEntryArrayList()).get(randomInt);
//Adds new Entry to entryDraw Array
drawSet.add(randomEntry);
}
else{
}
}
ArrayList<Entry> entryDraw = new ArrayList<Entry>(drawSet);
You can use the HashSet to let you know if an index of the ArrayList has already been used.
If you want to pick 3 unique indices from the list, you initialize a HashSet to contain all the indices of the ArrayList. Then, each time you draw a random index, you check if the HashSet contains that index.
If it does, you know that this index hasn't been used yet, and you remove it from the HashSet.
If it doesn't, that index has already been used, so you draw a random index again.
You repeat the process until you have 3 unique indices that haven't been used before.
You could fix this by looping until the Set contains the desired numbers of winners.
Working example:
List<Integer> tickets = Arrays.asList(1, 2, 3, 4, 5);
Set<Integer> winners = new HashSet<Integer>();
Random random = new Random();
while (winners.size() < 3) {
winners.add(tickets.get(random.nextInt(tickets.size())));
}
This question already has answers here:
Randomly select an item from a list
(5 answers)
Closed 8 years ago.
Alright, I keep trying to oogle this but It keeps showing answers with a string array which I can't use. This is currently my code:
List<String> Shuffle = new ArrayList<String>();
if(EAmount == finalk){
Shuffle.add("Emerald");
}
if(DAmount == finalk){
Shuffle.add("Diamond");
}
if(GAmount ==finalk){
Shuffle.add("Gold");
}
if(IAmount == finalk){
Shuffle.add("Iron");
}
I can't find out how to get a random string from Shuffle. Please help!
BTW: The Amounts and finalk are integers
You can generate a random integer between zero and the size of the collection (exclusive), and then use it as an index to refer to the corresponding item of the collection.
int randIndex = new Random().nextInt(Shuffle.size()); //generate rand int [0, size[
String randString = Shuffle.get(randIndex); //get random string
It is the same as with Arrays, you just need to use the get Method:
Shuffle.get(random)
I am fairly new to Java, and I want to generate an array of random (x,y) coordinates of length 'number' that contains no duplicates. x or y values can be repeated, but there must be no repeated (x,y) coordinates. The output does not have to be Points, simply some way of holding x,y values for coordinates.
I can generate an array of random points, and have tried using a Set to ensure there are no duplicate values, but have run into problems. I tried using the condition "while (set.size)" and the 'add' method which should disallow duplicates, to create an output of the correct size which contains unique points.
This is the code:
Set<Point> set = new HashSet<Point>();
Random position = new Random();
Point test=new Point();
do{
test.x=position.nextInt(xx);
test.y=position.nextInt(yy);
//xx and yy are the random number limits called from another part of the code
set.add(test);
}
while (set.size()<number);
List<Object> list = new ArrayList<Object>(set);
Object[] coord = list.toArray();
This outputs an array of the correct length, but every element is the same. Can anyone offer any help?
Thanks
test points to the same variable in space everytime you loop, to fix that create a new instance inside the loop - not just once before it:
Set<Point> set = new HashSet<Point>();
Random position = new Random();
Point test;
do{
test = new Point();
test.x=position.nextInt(xx);
test.y=position.nextInt(yy);
//xx and yy are the random number limits called from another part of the code
set.add(test);
}
while (set.size()<number);
List<Object> list = new ArrayList<Object>(set);
Object[] coord = list.toArray();
You are modifying the same point object. However, since you change X and Y every time, you also changing hash code and equality of the point, so you end up placing the same object multiple times in the set. Interesting case.
try
do{
test = new Point();
test.x=position.nextInt(xx);
test.y=position.nextInt(yy);
//xx and yy are the random number limits called from another part of the code
set.add(test);
}
while (set.size()<number);
Value select Randomly but not repeated
Random rndm = new Random();
String[] selectedNumber = new String[15];
String[] sequanceNumber = {"1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"};
//*****FIRST LOOP START*****//
for(byte a = 0; a < 15;){
int temp = rndm.nextInt(15)+1;
//*****SECOND LOOP START*****//
for(byte b = 0; b < 15; b++){
String s4 = temp+"";
//*****CHECKING CONDITION START*****//
if(s4.equals(sequanceNumber[b]) ){
selectedNumber[a] = s4;
String s1 = sequanceNumber[b];
s1 = s1.replace(s1, " ");
sequanceNumber[b] = s1;
a++;
}
//*****CHECKING CONDITION END*****//
}
//*****SECOND LOOP END*****//
}
//*****FIRST LOOP END*****//
//*****PRINT ALL RANDOM VALUES BUT NOT REPEATED VALUES*****//
System.out.println(Arrays.toString(selectedNumber));