using System;
using System.Collections.Generic;
using System.Linq;
namespace MLEM.Extensions {
///
/// A set of extensions for dealing with
///
public static class RandomExtensions {
///
/// Gets a random entry from the given collection with uniform chance.
///
/// The random
/// The entries to choose from
/// The entries' type
/// A random entry
public static T GetRandomEntry(this Random random, ICollection entries) {
return RandomExtensions.GetRandomEntry(entries, random.NextSingle());
}
///
/// Returns a random entry from the given collection based on the specified weight function.
/// A higher weight for an entry increases its likeliness of being picked.
///
/// The random
/// The entries to choose from
/// A function that applies weight to each entry
/// The entries' type
/// A random entry, based on the entries' weight
/// If the weight function returns different weights for the same entry
public static T GetRandomWeightedEntry(this Random random, ICollection entries, Func weightFunc) {
return RandomExtensions.GetRandomWeightedEntry(entries, weightFunc, random.NextSingle());
}
///
public static T GetRandomWeightedEntry(this Random random, ICollection entries, Func weightFunc) {
return RandomExtensions.GetRandomWeightedEntry(entries, weightFunc, random.NextSingle());
}
///
/// Returns a random floating-point number that is greater than or equal to 0, and less than .
///
/// The random.
/// The (exclusive) maximum value.
/// A single-precision floating point number that is greater than or equal to 0, and less than .
public static float NextSingle(this Random random, float maxValue) {
return maxValue * random.NextSingle();
}
///
/// Returns a random floating-point number that is greater than or equal to , and less than .
///
/// The random.
/// The (inclusive) minimum value.
/// The (exclusive) maximum value.
/// A single-precision floating point number that is greater than or equal to , and less than .
public static float NextSingle(this Random random, float minValue, float maxValue) {
return (maxValue - minValue) * random.NextSingle() + minValue;
}
#if !NET6_0_OR_GREATER
///
/// Returns a random floating-point number that is greater than or equal to 0, and less than 1.
///
/// The random.
/// A single-precision floating point number that is greater than or equal to 0, and less than 1.
public static float NextSingle(this Random random) {
return (float) random.NextDouble();
}
#endif
internal static T GetRandomEntry(ICollection entries, float randomValue) {
// ElementAt internally optimizes for IList access so we don't have to here
return entries.ElementAt((int) (randomValue * entries.Count));
}
internal static T GetRandomWeightedEntry(ICollection entries, Func weightFunc, float randomValue) {
var goalWeight = randomValue * entries.Sum(weightFunc);
var currWeight = 0;
foreach (var entry in entries) {
currWeight += weightFunc(entry);
if (currWeight > goalWeight)
return entry;
}
throw new IndexOutOfRangeException();
}
internal static T GetRandomWeightedEntry(ICollection entries, Func weightFunc, float randomValue) {
var goalWeight = randomValue * entries.Sum(weightFunc);
var currWeight = 0F;
foreach (var entry in entries) {
currWeight += weightFunc(entry);
if (currWeight > goalWeight)
return entry;
}
throw new IndexOutOfRangeException();
}
}
}