I want to choose a random item from a set, but the chance of choosing any item should be proportional to the associated weight
Example inputs:
item weight
---- ------
sword of misery 10
shield of happy 5
potion of dying 6
triple-edged sword 1
So, if I have 4 possible items, the chance of getting any one item without weights would be 1 in 4.
In this case, a user should be 10 times more likely to get the sword of misery than the triple-edged sword.
How do I make a weighted random selection in Java?
There is now a class for this in Apache Commons: EnumeratedDistribution
where
itemWeights
is aList<Pair<Item,Double>>
, like (assuming Item interface in Arne's answer):or in Java 8:
Note:
Pair
here needs to beorg.apache.commons.math3.util.Pair
, notorg.apache.commons.lang3.tuple.Pair
.I would use a NavigableMap
You will not find a framework for this kind of problem, as the requested functionality is nothing more then a simple function. Do something like this:
If you need to remove elements after choosing you can use another solution. Add all the elements into a 'LinkedList', each element must be added as many times as it weight is, then use
Collections.shuffle()
which, according to JavaDocFinally, get and remove elements using
pop()
orremoveFirst()
Use an alias method
If you're gonna roll a lot of times (as in a game), you should use an alias method.
The code below is rather long implementation of such an alias method, indeed. But this is because of the initialization part. The retrieval of elements is very fast (see the
next
and theapplyAsInt
methods they don't loop).Usage
Implementation
This implementation:
Random
in each thread for maximum performance, useThreadLocalRandom
?);Anyways, here's the code. (Note that I maintain an up to date version of this class.)