1

I have a function that accepts a HashMap<String, HashSet<Integer>>. Now I want to get a random value from the HashMap but I don't know how to do this. Could you give me a hint?

The output should consist of a tuple containing the String and an Integer value.

Maarten Bodewes
  • 90,524
  • 13
  • 150
  • 263
Robert Stevens
  • 488
  • 1
  • 7
  • 21

4 Answers4

2

Knowing the size of the map, you could pick a random entry number, then iterate over the contents until you reach that entry. Example:

final Set<String> keys = allowedInput.keySet();
final int keyNumber = (int)(Math.random() * keys.size());
final Iterator<String> keyIterator = keys.iterator();

String randomKey = null;

for (int i = 0; i < keyNumber && keyIterator.hasNext(); i++) {
    randomKey = keyIterator.next();
}

if (randomKey == null) {
    // This should not happen unless the map was empty, or it was modified
    // externally.  Handle the potential error case accordingly.
}

final HashSet<Integer> value = allowedInput.get(randomKey);

// `value` now contains a random element from the `allowedInput` map.

If you want to retrieve a random Integer element from the resulting HashSet<Integer>, then you can adapt the same technique: simply pick a random element number based on the size of the set, and iterate over the contents until you find it.

Mike Strobel
  • 25,075
  • 57
  • 69
1

If you want to repeatedly get random values, you could shuffle the set, and then go through it in order.

See Picking a random element from a set

Community
  • 1
  • 1
Ari
  • 1,974
  • 19
  • 30
1

I've created a generic solution that utilizes the answer of Mike and SecureRandom, and includes explicit null and bounds checking, as well as a quick return for singleton collections (not much to choose there).

public static <T> T getRandomElement(Collection<T> collection) {
    if (collection == null || collection.isEmpty()) {
        throw new IllegalArgumentException("Collection should not be null or empty");
    }
    if (collection.size() == 1) {
        return collection.iterator().next();
    }

    // it would be beneficial to make this a field when used a lot
    final Random random = new SecureRandom();
    final int randomIndex  = random.nextInt(collection.size());

    // optimization for list instances, use optimized indexing
    if (collection instanceof List) {
        final List<T> list = (List<T>) collection;
        return list.get(randomIndex);
    }

    int seen = 0;
    for (T e : collection) {
        if (seen++ == randomIndex) {
            return e;
        }
    }
    throw new IllegalStateException("Collection size was altered during operation");
}

Now you can simply retrieve a String and Integer by first selecting a key value from the key set, taking the value and choosing a random integer from that.

String key = getRandomElement(aMap.keySet());
Integer value = getRandomElement(aMap.get(key));
Maarten Bodewes
  • 90,524
  • 13
  • 150
  • 263
  • Note that this does allow for elements to be returned more than once obviously, check answers that shuffle the elements of a collection to get the elements just once. – Maarten Bodewes Nov 25 '13 at 00:31
0

thx evry one for the help i got i working now this is the code i used

final Set<String> keys = allowedInput.keySet();
        int keyNumber = (int)(random.nextInt(keys.size()));
        final Iterator<String> keyIterator = keys.iterator();

        String key = null;

        for (int i = 0; i <= keyNumber; i++) {
            key = keyIterator.next();
        }

        if (key == null) {
            // handle empty map
        }

        HashSet<Integer> field = allowedInput.get(key);

        final int fieldNumber = (int)(random.nextInt(field.size()));
        int fieldID = 0;
        int i = 0;
        for(Object obj : field)
        {

            if (i == fieldNumber)
            {
                //fieldID =  Integer.parseInt(obj.toString());
                fieldID =  (int)obj;
                break;
            }
            i = i + 1;

        }

        // Start constructing the userinput
        // Note: we need an instance of the UserInputSystem to create the UserInput instance!
        UserInputSystem userInputSystem = new UserInputSystem();
        UserInput input = userInputSystem.new UserInput(fieldID, key);
        System.err.println("ai fieldID = "+fieldID+" key = "+key);
Robert Stevens
  • 488
  • 1
  • 7
  • 21
  • It's good to know that you've solved your issue. There is no direct need to post your application here though. We're OK with knowing the techniques :). By the way, what about creating a method `getRandomElement(Set): T`? – Maarten Bodewes Nov 24 '13 at 21:15
  • i know but its always nice for other people with the same problem – Robert Stevens Nov 24 '13 at 23:15