I have a value, say 20010. I want to randomly divide this value over 24 hours. So basically split the value into a 24 slot big array where all slots are randomly big.
Wh
Assuming that you don't want to have much (any) control over the distribution of sizes, here's an approach that would work (pseudo-code).
Notes
Here's another solution that I think would work very well for this. Each time the method is called, it will return another set of randomly distributed values.
public static IEnumerable<int> Split(int n, int m)
{
Random r = new Random();
int i = 0;
var dict = Enumerable.Range(1, m - 1)
.Select(x => new { Key = r.NextDouble(), Value = x })
.OrderBy(x => x.Key)
.Take(n - 2)
.Select(x => x.Value)
.Union(new[] { 0, m })
.OrderBy(x => x)
.ToDictionary(x => i++);
return dict.Skip(1).Select(x => x.Value - dict[x.Key - 1]);
}
I tried the solutions from David and dahlbyk but had no luck. So here is what I came up with after reading the answer from mjv:
public static class IntExtensions
{
public static IEnumerable<int> Split(this int number, int parts)
{
var slots = Enumerable.Repeat(0, parts).ToList();
var random = new Random();
while (number > 0)
{
var slot = random.Next(0, parts);
slots[slot]++;
number--;
}
return slots;
}
}
Another option would be to generate a random number between 0 and the target number. Then, add each "piece" to a list. Choose the largest "piece" and cut it in two, using another random number. Select the largest from the list (now with three pieces), and continue until you have the desired number of pieces.
List<int> list = new List<int>();
list.Add(2010);
Random random = new Random();
while (list.Count() < 24)
{
var largest = list.Max();
var newPiece = random.Next(largest - 1);
list.Remove(largest);
list.Add(newPiece);
list.Add(largest - newPiece);
}
class Numeric
def n_rands(n)
raw = (1..n).map { |x| rand }
raw.map { |x| x * to_f / raw.sum.to_f }.map { |x| x.to_i }.tap do |scaled|
scaled[-1] = self - scaled[0..-2].sum
end
end
end
puts 1000.n_rands(10).inspect # [22, 70, 180, 192, 4, 121, 102, 179, 118, 12]
This is fun. Inspired by David, here's an implementation of mjv's solution using only LINQ-provided operators. Since David's Dictionary key is just an index, we can use an array instead for the Pairwise functionality:
var r = new Random();
var a = Enumerable.Repeat(null, n - 1) // Seq with (n-1) elements...
.Select(x => r.Next(1, m)) // ...mapped to random values
.Concat(new [] { 0, m })
.OrderBy(x => x)
.ToArray();
return a.Skip(1).Select((x,i) => x - a[i]);