C# 使用C在24个随机大小的零件中分割值#

C# 使用C在24个随机大小的零件中分割值#,c#,C#,我有一个值,比如20010。我想把这个值随机除以24小时。所以基本上把值分成一个24插槽的大数组,其中所有插槽都是随机大的 使用C#解决这个问题的好方法是什么?索引越高,随机性就越小。 如果需要,您可以随机化列表位置?这取决于你需要用它做什么 int initialValue = 20010; var values = new List<int>(); Random rnd = new Random(); int currentRemainder = initialValue;

我有一个值,比如20010。我想把这个值随机除以24小时。所以基本上把值分成一个24插槽的大数组,其中所有插槽都是随机大的


使用C#解决这个问题的好方法是什么?

索引越高,随机性就越小。 如果需要,您可以随机化列表位置?这取决于你需要用它做什么

int initialValue = 20010;
var values = new List<int>();

Random rnd = new Random();
int currentRemainder = initialValue;

for (int i = 0; i < 21; i++)
{
    //get a new value;
    int val = rnd.Next(1, currentRemainder - (21 - i));

    currentRemainder -= val;
    values.Add(val);
}

values.Add(currentRemainder);

//initialValue == values.Sum()
int initialValue=20010;
var值=新列表();
随机rnd=新随机();
int currentRequires=初始值;
对于(int i=0;i<21;i++)
{
//获得新的价值;
int val=rnd.Next(1,当前余数-(21-i));
当前余数-=val;
值。添加(val);
}
值。添加(当前余数);
//initialValue==values.Sum()
在1到20009范围内随机抽取23(不是24)个数字(没有重复)。将0和20010添加到列表中并对这些数字进行排序,每两个连续数字之间的差值将为您提供一个插槽值


在线方法也可以通过一次提取一个值,然后从“pot”中减去该值,当该值大于剩余值时重新提取。然而,这种方法可能导致槽尺寸的更大偏差

假设您不想对大小的分布有太多(任何)控制,这里有一个可行的方法(伪代码)

  • 创建一个包含24个随机值的列表,按任意比例生成
  • 查找此列表的总和
  • 通过缩放24个随机值来创建最终列表
  • 注释

    • 如果使用浮点运算,则可能会偏离1或2。为了避免这种情况,不要使用缩放来完成最后一个值,而是用剩余的总值填充它
    • 如果您确实需要对分发进行更严格的控制,请使用不同的方法生成初始数组,但其他方法不需要更改

    如果您想确保在没有太多分析的情况下不会对流程产生偏差,您可以创建一个24元素数组,将每个元素初始化为0,然后将1随机添加到其中一个元素中20010次


    这完全取决于您希望看到的分布类型,但我认为目前推荐的任何其他技术都不会导致长达一小时的“桶”在统计上无法区分。

    以下是使用mjv算法的函数解决方案:

    static int[] GetSlots(int slots, int max)
    {
        return new Random().Values(1, max)
                           .Take(slots - 1)
                           .Append(0, max)
                           .OrderBy(i => i)
                           .Pairwise((x, y) => y - x)
                           .ToArray();
    }
    
    public static IEnumerable<int> Values(this Random random, int minValue, int maxValue)
    {
        while (true)
            yield return random.Next(minValue, maxValue);
    }
    
    public static IEnumerable<TResult> Pairwise<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TSource, TResult> resultSelector)
    {
        TSource previous = default(TSource);
    
        using (var it = source.GetEnumerator())
        {
            if (it.MoveNext())
                previous = it.Current;
    
            while (it.MoveNext())
                yield return resultSelector(previous, previous = it.Current);
        }
    }
    
    public static IEnumerable<T> Append<T>(this IEnumerable<T> source, params T[] args)
    {
        return source.Concat(args);
    }
    
    static int[]GetSlots(int-slots,int-max)
    {
    返回新的Random()值(1,最大值)
    .Take(插槽-1)
    .Append(0,最大值)
    .OrderBy(i=>i)
    .成对((x,y)=>y-x)
    .ToArray();
    }
    公共静态IEnumerable值(此随机值、int-minValue、int-maxValue)
    {
    while(true)
    收益率返回随机。下一步(minValue,maxValue);
    }
    公共静态IEnumerable成对(此IEnumerable源、Func resultSelector)
    {
    TSource-previous=默认值(TSource);
    使用(var it=source.GetEnumerator())
    {
    if(it.MoveNext())
    previous=it.Current;
    while(it.MoveNext())
    收益返回结果选择器(previous,previous=it.Current);
    }
    }
    公共静态IEnumerable追加(此IEnumerable源,参数T[]args)
    {
    返回source.Concat(args);
    }
    
    另一个选项是生成一个介于0和目标数之间的随机数。然后,将每个“片段”添加到列表中。选择最大的一块,用另一个随机数把它切成两半。从列表中选择最大的一个(现在有三个),然后继续,直到获得所需的数量

    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);
    }
    
    List List=新列表();
    列表。添加(2010年);
    随机=新随机();
    while(list.Count()<24)
    {
    var Max=list.Max();
    var newPiece=random.Next(最大值-1);
    删除(最大的);
    列表。添加(新件);
    列表。添加(最大-新件);
    }
    
    我已经计算了这里提出的每种算法在100次试验中24个桶的平均大小。我认为有趣的是,四分之三的人似乎确实平均每个bucket产生20010/24个项目,但我描述的简单方法最快收敛到这个平均值。这对我来说有一些直观的意义。这种方法类似于在24个桶上随机下雪,因此可能会产生大小大致相等的桶。其他的更像是在一段木头上随意砍

    Bevan:  [751, 845, 809, 750, 887, 886, 838, 868, 837, 902, 841, 812, 818, 774, 815, 857, 752, 815, 896, 872, 833, 864, 769, 894]
    Gregory:  [9633, 5096, 2623, 1341, 766, 243, 159, 65, 21, 19, 16, 4, 3, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2]
    mjv:  [895, 632, 884, 837, 799, 722, 853, 749, 915, 756, 814, 863, 842, 642, 820, 805, 659, 862, 742, 812, 768, 816, 721, 940]
    peterallenwebb:  [832, 833, 835, 829, 833, 832, 837, 835, 833, 827, 833, 832, 834, 833, 836, 833, 838, 834, 834, 833, 834, 832, 836, 830]
    
    下面是python代码: 随机输入

    N = 20010;
    
    def mjv():
        gaps = [ random.randrange(0, N) for i in range(0, 24) ]
        gaps = gaps + [0, N]
        gaps.sort()
        value = [ gaps[i+1] - gaps[i] for i in range(0, 24) ]
        return value
    
    def gregory():
        values = []
        remainingPortion = N
    
        for i in range(0, 23):
            val = random.randrange(1, remainingPortion - (23 - i))
            remainingPortion = remainingPortion - val
            values.append(val)
    
        values.append(remainingPortion)
    
        return values
    
    
    def peterallenwebb():
        values = [0  for i in range(0, 24) ]
    
        for i in range(0, N):
            k = random.randrange(0, 24)
            values[k] = values[k] + 1 
    
        return values
    
    def bevan():
        values = [];
        sum = 0.0
    
        for i in range(0, 24):
            k = random.random()
            sum = sum + k
            values.append(k);
    
        scaleFactor = N / sum
    
        for j in range(0, 24):
            values[j] = int(values[j] * scaleFactor)
    
        return values
    
    
    def averageBucketSizes(method):
        totals = [0 for i in range(0, 24)]
        trials = 100
    
        for i in range(0,trials):
            values = method()
    
            for j in range(0, 24):
                totals[j] = totals[j] + values[j]      
    
        for j in range(0, 24):
            totals[j] = totals[j] / trials
    
        return totals;
    
    
    print 'Bevan: ', averageBucketSizes(bevan)
    print 'Gregory: ', averageBucketSizes(gregory)
    print 'mjv: ', averageBucketSizes(mjv)
    print 'peterallenwebb: ', averageBucketSizes(peterallenwebb)
    

    如果你看到任何错误,请告诉我。我将重新运行。

    这里有另一个解决方案,我认为它非常适用于此。每次调用该方法时,它将返回另一组随机分布的值

    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]);
    }
    
    公共静态IEnumerable拆分(int n,int m)
    {
    随机r=新随机();
    int i=0;
    var dict=可枚举范围(1,m-1)
    .Select(x=>new{Key=r.NextDouble(),Value=x})
    .OrderBy(x=>x.Key)
    .Take(n-2)
    .选择(x=>x.Value)
    .Union(新[]{0,m})
    .OrderBy(x=>x)
    .ToDictionary(x=>i++);
    返回dict.Skip(1)。选择(x=>x.Value-dict[x.Key-1]);
    }
    
    这很有趣。受David的启发,这里是mjv解决方案的一个实现,仅使用LINQ提供的操作符。由于David的Dictionary键只是一个索引,我们可以使用数组代替成对功能:

    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]);
    

    我尝试了大卫和达尔贝克的解决方案,但没有成功。以下是我在阅读了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;
        }
    }
    
    公共静态类扩展
    {
    公共静态IEnumerable拆分(此整数,整数部分)
    {
    var slots=Enumerable.Repeat(0,parts.ToList();
    var random=新的random();
    而(数量>0)
    {
    var插槽=随机。下一个(0,零件);
    插槽[插槽]+;
    数字--;
    }
    雷图
    
    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;
        }
    }