Question

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.

Was it helpful?

Solution

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.

OTHER TIPS

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

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));

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);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top