来自另一个列表的随机对象列表c#

时间:2014-09-19 13:10:43

标签: c# list random

我有一个列表private List<HeroStats> allHeroes;

和列表private List<Team> allTeams;

在我填充我的列表之后&#39; allHeroes&#39;与英雄一起,我想用这种方法创建5个随机英雄的团队:

public Team createTeam()
{
    int index=0;
    Team t = new Team();
    Random rnd = new Random();
    int cap = allHeroes.Count;
    while (t.count() < 5)
    {
        index = rnd.Next(0, cap);
        t.Add(allHeroes.ElementAt(index));
    }
    return t;
}

这创造了一个完美的团队,但如果我想创建更多的团队,它将一次又一次地生成同一个团队。
我也有一个方法

public List<HeroStats> print()
{
    StringBuilder sb = new StringBuilder();
    List<HeroStats> l = new List<HeroStats>();
    foreach (HeroStats h in team)
    {
         sb.AppendLine(h.HeroName);
         l.Add(h);
    }
    Console.WriteLine(sb.ToString());
    return l; 
}

哪个应该打印出团队中英雄的名字。

如果我产生很多人,为什么我会得到同一个团队?


为了创建多个团队,我使用:

Team a = new Team();
            for (int i = 0; i < 2000; i++)
            {
                a = createTeam();
               allTeams.Add(a);

         }

5 个答案:

答案 0 :(得分:2)

正在创建相同的团队,因为Random实例是在方法中创建的,如果您非常快地调用createTeam,则会导致相同的种子(default Random constructor使用当前时间作为种子)。您可以通过将Random传递给方法或使用字段来避免这种情况:

public Team createTeam(Random rnd) // as an aside, you should call it CreateRandomTeam
{
    int index=0;
    Team t = new Team();
    int cap = allHeroes.Count;
    while (t.count() < 5)
    {
        index = rnd.Next(0, cap);
        t.Add(allHeroes.ElementAt(index));
    }
    return t;
}

现在您必须确保始终将相同的Random实例传递给createTeam

例如你的循环:

Random rnd = new Random();
Team a = new Team();
for (int i = 0; i < 2000; i++)
{
    a = createTeam(rnd);
    allTeams.Add(a);
}

MSDN在备注部分也提到了这一点:

  

默认种子值源自系统时钟且有限   解析度。因此,创建的不同Random对象   通过调用默认构造函数来关闭连续   相同的默认种子值,因此,将产生相同的   随机数集。使用单个可以避免此问题   随机对象生成所有随机数。你也可以解决   它通过修改系统时钟返回的种子值然后   明确地向Random(Int32)提供这个新的种子值   构造

答案 1 :(得分:1)

你需要

 Random rnd = new Random();

之外
public Team createTeam()
{

}

也许在rnd中解析为参数。

答案 2 :(得分:1)

来自Random

documentation
  

默认种子值源自系统时钟并具有有限的分辨率。因此,通过调用默认构造函数紧密连续创建的不同Random对象将具有相同的默认种子值,因此将生成相同的随机数集。

如果您在紧急循环中调用createTeam()来创建随机团队,那么由于Random的实例创建如此接近,您最终会得到相同的随机数集彼此和相同的种子。

一种可能的解决方案是取出Random类型的对象并使其成为类级字段。

public static class RandomTeamCreator
{
    private static readonly Random _random = new Random();
    public Team CreateTeam()
    {
        // create team using _random
    }
}

答案 3 :(得分:1)

  

如果我生成很多人,为什么我会成为同一个团队?

可能是因为创建团队之间的时间不足以让内部时钟创建新的随机种子。

我会向createTeam添加“种子”参数:

public Team createTeam(int seed)
{
    int index=0;
    Team t = new Team();
    Random rnd = new Random(seed);
    int cap = allHeroes.Count;
    while (t.count() < 5)
    {

        index = rnd.Next(0, cap);
        t.Add(allHeroes.ElementAt(index));
    }
    return t;
}

然后在eloop之外使用另一个 Random生成种子

for(int 1 = 0; i < 10; i++)
{
   Random r = new Random(0);
   int seed = r.Next();
   createTeam(int seed);
}

如果你想保留原始签名,只需添加一个重载:

public Team createTeam()
{
    return createTeam(new Random().Next());
}

SIDE NOTE

你可能想要一个“混乱”的英雄团队,而不是“随机”,因为“随机”你可以两次获得同一个英雄。如果是这种情况,那么只需使用随机顺序的“order by”:

public Team createTeam(int seed)
{
    Random rnd = new Random(seed);

    Team t = new Team();

    var shuffled = allHeroes.OrderBy(rnd.Next()).Take(5);
    foreach(var hero in shuffled)
        t.Add(hero);

    return t;
}

答案 4 :(得分:0)

如果您在大致相同的时间创建了许多Random个实例,则它们可能会生成相同的数字。相反,在其他地方创建一个Random并从算法中调用其Next方法。