Skip to content

Instantly share code, notes, and snippets.

@Scarsz
Last active June 12, 2018 14:47
Show Gist options
  • Save Scarsz/9881267eac98dcb946314e54c2403363 to your computer and use it in GitHub Desktop.
Save Scarsz/9881267eac98dcb946314e54c2403363 to your computer and use it in GitHub Desktop.
Get a random object from a given map containing objects and their probabilities
1,000,000 iterations took 271ms to calculate
ten chances generated 181764 times = 18%
nine chances generated 163178 times = 16%
eight chances generated 146151 times = 14%
seven chances generated 127031 times = 12%
six chances generated 109405 times = 10%
five chances generated 91076 times = 9%
four chances generated 72484 times = 7%
three chances generated 54386 times = 5%
two chances generated 36190 times = 3%
one chances generated 18335 times = 1%
package com.scarsz.playground;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Made by Scarsz
*
* @in /dev/hell
* @on 3/5/2017
* @at 11:21 AM
*/
public class RandomObjectFromProbabilities {
/**
* {@link Random} object to generate random numbers from.
*/
private static Random random = new Random();
/**
* The map of all our possible random objects to be generated along with their chance of being selected.<br>
* Lower numbers have a lower chance of being selected & vice versa.
*/
private static Map<Object, Integer> items = new LinkedHashMap<Object, Integer>() {{
put("one chances", 1);
put("two chances", 2);
put("three chances", 3);
put("four chances", 4);
put("five chances", 5);
put("six chances", 6);
put("seven chances", 7);
put("eight chances", 8);
put("nine chances", 9);
put("ten chances", 10);
}};
/**
* Get a random object from the given list with given probabilities of being selected
* @param items Items to choose from
* @return Randomly selected key of an entry from the given map based on the entry's probability (entry value)
*/
private static Object getRandomObjectFromProbabilities(Map<Object, Integer> items) {
if (items == null) throw new NullPointerException("Null items map supplied!");
if (items.size() == 0) throw new RuntimeException("Not enough items to generate from! (0)");
int totalSum = items.values().stream().mapToInt(Integer::intValue).sum();
int count = random.nextInt(totalSum) + 1;
Object currentObject = null;
while (count > 0) {
for (Map.Entry<Object, Integer> entry : items.entrySet()) {
currentObject = entry.getKey();
count -= entry.getValue();
if (count <= 0) return currentObject;
}
}
// it should never reach this point, but, if it does, default to the first given item
return currentObject != null ? currentObject : items.keySet().iterator().next();
}
public static void main(String[] args) {
long startMs = System.currentTimeMillis();
long iterations = 1000000;
Map<String, AtomicInteger> results = new HashMap<>();
for (int i = 0; i < iterations; i++) {
String result = (String) getRandomObjectFromProbabilities(items);
if (results.containsKey(result)) results.get(result).incrementAndGet();
else results.put(result, new AtomicInteger(1));
}
System.out.println(iterations + " iterations took " + (System.currentTimeMillis() - startMs) + "ms to calculate\n");
for (Map.Entry<String, AtomicInteger> result : results.entrySet())
System.out.println(result.getKey() + " generated " + result.getValue() + " times = " + ((int) (((double) result.getValue().intValue() / iterations) * 100)) + "%");
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment