C# 使用C在24个随机大小的零件中分割值#
我有一个值,比如20010。我想把这个值随机除以24小时。所以基本上把值分成一个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;
使用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”中减去该值,当该值大于剩余值时重新提取。然而,这种方法可能导致槽尺寸的更大偏差 假设您不想对大小的分布有太多(任何)控制,这里有一个可行的方法(伪代码)
- 如果使用浮点运算,则可能会偏离1或2。为了避免这种情况,不要使用缩放来完成最后一个值,而是用剩余的总值填充它
- 如果您确实需要对分发进行更严格的控制,请使用不同的方法生成初始数组,但其他方法不需要更改
这完全取决于您希望看到的分布类型,但我认为目前推荐的任何其他技术都不会导致长达一小时的“桶”在统计上无法区分。以下是使用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;
}
}