请考虑以下代码.基本思想是返回一个逗号分隔的20个数字列表,其中任何一个数字都可以是介于0和最大允许值之间的值.在每次通过循环时,列表中下一个值允许的潜在最大值减少了所选择的最后一个随机值.
所以它有效...但它很糟糕.问题是它总是会产生这样的输出:
"22,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0"
"17,3,3,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0"
"23,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0"
如何修改以允许在整个范围内更均匀地分配值?
public static string RandomRangeOfValuesMaker(int total)
{
var remainingTotal = total + 1;
const int numberOfValues = 20;
var rand = new Random();
var builder = new StringBuilder();
for (var i = 1; i < numberOfValues + 1; i++)
{
var currentRandomNumber = rand.Next(remainingTotal);
remainingTotal = remainingTotal - currentRandomNumber;
builder.Append(currentRandomNumber + ",");
}
var rangeOfValues = builder.ToString().Remove(builder.ToString().Length - 1);
return rangeOfValues;
}
Run Code Online (Sandbox Code Playgroud)
Eri*_*ert 10
更新:我误解了对问题的严重限制; 我的原始答案解决了"按降序生成小于m的随机数"的问题.原始答案附于下方.
实际问题是"生成数字m到n个部分的随机分区".
有很多方法可以做到这一点.这是一个; 时间为O(m),空间为O(n).你能提高吗?
static Random random = new Random();
static IEnumerable<int> Partition(int number, int parts) {
int[] partition = new int[parts];
for(int i = 0; i < number; ++i)
partition[random.Next(parts)] += 1;
return partition;
}
Run Code Online (Sandbox Code Playgroud)
算法是:我们有parts
板条箱和number
苹果; 我们随机将每个苹果扔进箱子里,直到我们没有苹果,然后我们将所有苹果分开.
现在你的程序是单线程
Partition(maxNumber, 20).OrderByDescending(x=>x).CommaSeparated();
Run Code Online (Sandbox Code Playgroud)
使用下面的帮助函数.
在这个解决方案和Kyle的解决方案中要注意的关键不是生成分区的算法 - 就像我说的,有很多方法可以做到这一点.相反,关键是不要试图在一个功能中做太多.当你试图确保sum属性以及单调性和逗号分离都在同一个地方时,你出错了.排序20个数字很便宜; 外包问题.逗号分隔一堆东西很便宜; 外包那个问题.编写小函数,每个函数都做好一件事,然后将它们组合成更大的函数.
如何修改以允许在整个范围内更均匀地分配值?
选择数第一,并随后对其进行排序.
让我们分解吧.第一:随机数的无限序列:
private static Random random = new Random();
public static IEnumerable<int> RandomNumbers(int max)
{
while(true) yield return random.Next(max);
}
Run Code Online (Sandbox Code Playgroud)
既然你有你的程序成为一个单行.
public static string RandomRangeOfValuesMaker(int maxNumber)
{
return string.Join(",", RandomNumbers(maxNumber).Take(20).OrderByDescending(x=>x));
}
Run Code Online (Sandbox Code Playgroud)
每当你做一些涉及序列的事情时,我可以使用内置的序列操作符来表达我想要的工作流程吗?我可以构建自己的序列运算符吗?
例如,我们可以使另一个序列运算符单行:
public static string CommaSeparated<T>(this IEnumerable<T> items)
{
return string.Join(",", items);
}
Run Code Online (Sandbox Code Playgroud)
现在你的程序变得更加优雅:
public static string RandomRangeOfValuesMaker(int maxNumber)
{
return RandomNumbers(maxNumber)
.Take(20)
.OrderByDescending(x=>x)
.CommaSeparated();
}
Run Code Online (Sandbox Code Playgroud)
你想要什么?20个随机数,按降序排列,用逗号分隔.那么你的程序应该怎么读?它应该说我想要20个随机数降序,用逗号分隔.编写程序,使其看起来像是要解决的问题的描述.它更容易理解,更易于维护,更容易看出它是正确的.