2

I have a group of fixed numbers from 1 to 5. These are added into a Map as follows:

map.put(1, 1);
map.put(2, 2);
map.put(3, 3);
map.put(4, 4);
map.put(5, 5);

From that I randomly take two numbers that I remove from the Map<Integer, Integer> leaving three numbers.

map.remove(Rwiner);
map.remove(Rsec);

This would leave me three numbers like 2,1,4. I want to pick out a random number from that. What should i do?

Dhruv Gairola
  • 9,102
  • 5
  • 39
  • 43
Siten
  • 4,515
  • 9
  • 39
  • 64
  • @DownVoters please leave the comment... thanks – Siten Jul 30 '11 at 07:30
  • You're being downvoted because your question is unclear and it's hard to understand what you mean because of your bad use of English. – Sophie Alpert Jul 30 '11 at 07:32
  • 3
    @Ben: if that is true I don't approve. People should not be downvoted because they're not fluent in english. – Richard H Jul 30 '11 at 07:49
  • 1
    I edited the question a bit. Hope it reflects what you were asking @Siten and helps you improve the quality of your questions in future. I have a question. Do you just need to remove one random number at a time or must two random numbers be removed in the first step? – James P. Jul 30 '11 at 08:13

3 Answers3

3

Are you asking how in Java to select three distinct random integers in the range 1..5?

How about creating a List with the values 1, 2, 3, 4, 5, then calling Collections.shuffle then just looking at the first three elements?

Source code:

import java.util.Collections;
import java.util.Arrays;
import java.util.List;
public class ThreeOfFive {
    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            System.out.println(randomThreeOfFive());
        }
    }

    /**
     * Returns a list of three integers randomly selected from 1, 2, 3, 4, 5.
     */
    public static List<Integer> randomThreeOfFive() {
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
        Collections.shuffle(list);
        return list.subList(0, 3);
    }
}
Ray Toal
  • 86,166
  • 18
  • 182
  • 232
  • *i want to pick up **a** number*... I don't interpret it as if he wants three numbers... – aioobe Jul 30 '11 at 08:03
  • Upvoted. I like alternative solutions that make use of the API. – James P. Jul 30 '11 at 08:13
  • @aioobe: [`Collections.shuffle`](http://download.oracle.com/javase/6/docs/api/java/util/Collections.html) does random permutations. If the aim is to go through all the numbers one at a time then selecting a number would be as simple as taking the first element in a ´List´ after a shuffle. This does bring the question of whether a shuffle like this could be considered as equivalent to individual random selections. I'll post a question on SO on the topic. – James P. Jul 30 '11 at 08:17
  • 1
    @James i like the creative use of the api. unfortunately, each shuffle runs in linear time. this means that if you want to remove multiple numbers, this solution runs at O(n^2). my answer runs at O(n). – Dhruv Gairola Jul 30 '11 at 08:23
  • 1
    @Dhruv Gairola: You're right. Complexity would be higher. It would like swapping all records in a database table instead of selecting a random id. – James P. Jul 30 '11 at 08:28
  • @James although, if you think about it, you would only have to shuffle once, and subsequently you could pick out however many numbers you wanted. so this would now become O(n). so you don't need to shuffle each time- only once. in which case, ray's answer seems pretty good... – Dhruv Gairola Jul 30 '11 at 08:31
  • 1
    @James, @Dhruv, @aioobe - `Collections.shuffle` _does_ run in linear time, it explicitly says so in the source code: http://www.docjar.com/html/api/java/util/Collections.java.html. Waiting on @Siten's answer. If he does want only _one_ result, then there is a O(1) solution called `random.nextInt(5)+1` :-) – Ray Toal Jul 30 '11 at 08:37
  • Run-time aside, I've posted a question on whether they could be seen as equivalent. A linked question says that the Collections method implements a Fisher-Yates shuffle. This appears to combine the use of the [RandomAccess](http://download.oracle.com/javase/1.4.2/docs/api/java/util/RandomAccess.html) interface and a simple swap function. http://stackoverflow.com/questions/6882081/can-a-collections-shuffle-be-considered-equivalent-to-a-series-of-randoms/ – James P. Jul 30 '11 at 09:16
2

Something like this perhaps:

// Setup
Map<Integer, Integer> map = new HashMap<Integer, Integer>();

map.put(1, 1);
map.put(2, 2);
map.put(3, 3);
map.put(4, 4);
map.put(5, 5);

int Rwiner = 3, Rsec = 5;

map.remove(Rwiner);
map.remove(Rsec);

// Get random entry from current map.
Random rnd = new Random();
int randomIndex = rnd.nextInt(map.size());
int randomKey = new ArrayList<Integer>(map.keySet()).get(randomIndex);
System.out.printf("Random entry: %d -> %d", randomKey, map.get(randomKey));
aioobe
  • 413,195
  • 112
  • 811
  • 826
  • Upvoted. Here's some additional information on how to generate random numbers: [Generate random numbers](http://www.javapractices.com/topic/TopicAction.do?Id=62) – James P. Jul 30 '11 at 08:24
2

Uh, from what little I understand, you need to keep removing a number randomly from your map. I think an array is better suited for your task.

Step 1: Convert map into an array. i.e. use values() and toArray().    
Step 2: Use map.size() as the upper bounds on nextInt(int n) on a Random 
        object.    
Step 3: Use the value from step 2 to find the corresponding index of the 
        randomly selected value on the array generated in step 1.

However, each time you remove an object randomly, you will have to repeat these steps, and therefore, keep creating a new array each time (or as aioobe suggested, you will need to keep copying the set values into an arraylist) and this is wasteful. Lets see if we can do this more efficiently only using one array (and not creating a new one each time):

Example:

Array: [1] [2] [3]
Randomly select index 2: [3] [?] [?]
Swap dead index: [x] [2] [1]

Array: [x] [2] [1]
Randomly select index 2: [1] (obv. it doesn't matter if you select index 1)
Swap dead index: [x] [x] [2]

So the above method is more efficient as the array knows that the first k elements are dead. Implementation is as follows:

public static void randArray(int[] arr, int pickHowMany) {
   //error checking
   if(pickHowMany > arr.length())
      return;
   int temp, index;
   Random rand = new Random();
   for (int i = 0; i < pickHowMany; i++){
      index = rand.nextInt(arr.length - i) + i;
      temp = arr[i];
      arr[i] = arr[index];
      arr[index] = temp;
   }
}

So the above method is way more efficient as it works on the same array, rather than creating a new array of arraylist each time. Plus, you can pick multiple numbers by changing the pickHowMany parameter- the method runs in O(n). Do take note that it works on arrays, so all you need to do is convert your map into an array once.

Ray's solution is good too, but it is inefficient if you shuffle each time you want to pick one (i.e. O(n^2)). However, if you shuffle only once, Ray's solution runs at O(n) and you can subsequently pick how many ever numbers you want from the list. So this is again at O(n) for multiple numbers, which is the same complexity as mine although, traversing through a list to remove the first n numbers is far clunkier than selecting the first n numbers of an array.

Dhruv Gairola
  • 9,102
  • 5
  • 39
  • 43