Changed getWeighted() to accept a Map<T, ? extends Number>.

git-svn-id: https://samskivert.googlecode.com/svn/trunk@2914 6335cc39-0255-0410-8fd6-9bcaacd3b74c
This commit is contained in:
ray.j.greenwell
2010-10-12 20:26:02 +00:00
parent 485e5e160d
commit 880e785a8a
+14 -6
View File
@@ -149,16 +149,24 @@ public class Randoms
* @throws NullPointerException if the map is null. * @throws NullPointerException if the map is null.
* @throws IllegalArgumentException if the sum of the weights is not positive. * @throws IllegalArgumentException if the sum of the weights is not positive.
*/ */
public <T> T getWeighted (Map<T, Integer> valuesToWeights) public <T> T getWeighted (Map<T, ? extends Number> valuesToWeights)
{ {
// TODO: validation? // TODO: validate each weight to ensure it's not below 0
int idx = _r.nextInt(Folds.sum(0, valuesToWeights.values())); double sum = Folds.sum(0.0, valuesToWeights.values());
for (Map.Entry<T, Integer> entry : valuesToWeights.entrySet()) { if (sum <= 0) {
idx -= entry.getValue(); throw new IllegalArgumentException("The sum of the weights is not positive");
if (idx < 0) { }
// TODO: iterate all entries once, similarly to picking from an Iterable?
double d = _r.nextDouble() * sum;
for (Map.Entry<T, ? extends Number> entry : valuesToWeights.entrySet()) {
d -= entry.getValue().doubleValue();
if (d < 0) {
return entry.getKey(); return entry.getKey();
} }
} }
// TODO: due to rounding error when iteratively subtract doubles, it might
// be possible to fall out of the loop here. Remember the highest-weighted entry
// and return it? (returning the last entry could be incorrect if it had a weight of 0).
throw new AssertionError("Not possible"); throw new AssertionError("Not possible");
} }