In Java, given n Items, each with weight w, how does one choose a random Item from the collection with a chance equal to w?
Assume each weight is a double from 0.0 to 1.0, and that the weights in the collection sum to 1. Item.getWeight() returns the Item's weight.
Below is a randomizer that maintains precision in proportions as well:
With a
Item
class that contains agetWeight()
method (as in your question):With a
Map
and more generic method:If you want runtime selection efficiency then taking a little more time on the setup would probably be best. Here is one possible solution. It has more code but guarantees log(n) selection.
WeightedItemSelector Implements selection of a random object from a collection of weighted objects. Selection is guaranteed to run in log(n) time.
Range Implements range selection to leverage TreeMap selection.
WeightedItem simply encapsulates an item to be selected.
I think I've done it like that before... but there are probably more efficient ways to do this.
One elegant way would be to sample an exponential distribution http://en.wikipedia.org/wiki/Exponential_distribution where the weights will be the rate of the distribution (lambda). Finally, you simply select the smallest sampled value.
In Java this looks like this:
I am not sure whether this is more efficient than the other approaches, but if execution time is not the issue, it is a nicely looking solution.
And this is the same idea using Java 8 and Streams:
You can obtain the input weights stream for instance from a map by converting it with
.entrySet().stream()
.