我正在尝试编写一个程序来从US Census last name list中选择一个随机名称。列表格式为
Name Weight Cumulative line
----- ----- ----- -
SMITH 1.006 1.006 1
JOHNSON 0.810 1.816 2
WILLIAMS 0.699 2.515 3
JONES 0.621 3.136 4
BROWN 0.621 3.757 5
DAVIS 0.480 4.237 6
假设我将数据加载到类似
的结构中Class Name
{
public string Name {get; set;}
public decimal Weight {get; set;}
public decimal Cumulative {get; set;}
}
哪种数据结构最适合保存名称列表,以及从列表中选择随机名称但名称分布与现实世界相同的最佳方式。
如果它在数据结构上有所不同,我将只使用前10,000行。
我已经尝试过关于加权随机性的其他一些问题但我在将理论转化为代码时遇到了一些麻烦。我对数学理论知之甚少,所以我不知道这是一个“有或没有替代”的随机选择,我想要同一个名字能够不止一次出现,这就是那个意思。
答案 0 :(得分:6)
处理此问题的“最简单”方法是将其保存在列表中。
然后你可以使用:
Name GetRandomName(Random random, List<Name> names)
{
double value = random.NextDouble() * names[names.Count-1].Culmitive;
return names.Last(name => name.Culmitive <= value);
}
如果速度是一个问题,您可以存储一个仅包含Culmitive
值的单独数组。有了这个,您可以使用Array.BinarySearch
快速找到合适的索引:
Name GetRandomName(Random random, List<Name> names, double[] culmitiveValues)
{
double value = random.NextDouble() * names[names.Count-1].Culmitive;
int index = Array.BinarySearch(culmitiveValues, value);
if (index >= 0)
index = ~index;
return names[index];
}
可能最有效的另一种选择是使用C5 Generic Collection Library的tree classes之一。然后,您可以使用RangeFrom
查找相应的名称。这具有不需要单独收集的优点
答案 1 :(得分:3)
我创建了a C# library for randomly selected weighted items。
一些示例代码:
add
答案 2 :(得分:0)
我会说一个数组(如果你愿意,可以使用矢量)最好保留它们。对于加权平均值,找到总和,在零和总和之间选择一个随机数,然后选择累积值较小的姓氏。 (例如,这里,&lt; 1.006 =史密斯,1.006-1.816 =约翰逊等。
P.S。这是累积的。
答案 3 :(得分:0)
只是为了好玩,而且绝不是最佳的
List<Name> Names = //Load your structure into this
List<String> NameBank = new List<String>();
foreach(Name name in Names)
for(int i = 0; i <= (int)(name.Weight*1000); i++)
NameBank.Add(name.Name)
然后:
String output = NameBank[rand(NameBank.Count)];