【问题标题】:picking random name from text file in c# windows forms non repeatable从 c# windows 中的文本文件中选择随机名称形成不可重复
【发布时间】:2014-11-11 13:45:51
【问题描述】:

我想知道如何处理这段代码,目前正在开发锦标赛括号系统。

目前我创建了一个组合框,它从“log.txt”中获取所有行,txt 文件中有 16 行;然后我创建了一个分配按钮,应该将所有名称分配到 16 个名为 User1 --> User16 的文本框中,但是不能重复相同的名称。

我查看了“列表数组”和“字符串数组”,但我似乎被卡住了,因为我真的不知道要在代码中添加什么.

我的随机按钮现在看起来像这样:

private void assign_Click(object sender, EventArgs e)
    {
        int x;
        Random rnd = new Random();
        x = rnd.Next(0, 16);
        User1.Text = comboBox2.Items[x].ToString();
        x = rnd.Next(0, 16);
        User2.Text = comboBox2.Items[x].ToString();
        x = rnd.Next(0, 16);
        User3.Text = comboBox2.Items[x].ToString();
        x = rnd.Next(0, 16);
        User4.Text = comboBox2.Items[x].ToString();
        and so on untill i hit 
        x = rnd.Next(0, 16);
        User16.Text = comboBox2.Items[x].ToString();
        }

【问题讨论】:

    标签: c# windows winforms forms


    【解决方案1】:

    执行此操作的最简单但不一定最有效的方法之一是将所有字符串放入List<string> 并随机一个接一个地删除它们。如果您将所有文本框也放入一个集合中,这会更好。例如,给定一个名为 myStrings 的字符串列表和一个名为 myTextboxes 的文本框集合,您可以:

    for (var i=0; i < myStrings.Count; i++) 
    {
        var idx = rnd.Next(0, myStrings.Count);
        myTextboxes[i].Text = myStrings[idx];    // Note: we are assuming the two collections have 
                                                 // the same length
        myStrings.RemoveAt(idx);        
    }
    

    这很容易实现,也很容易做对,但效率不是很高(对于 16 个项目,这可能无关紧要),因为您的集合会反复调整大小。为了更有效的方法,首先使用Fisher-Yates shuffle 打乱您的字符串,然后将打乱字符串中的第一个条目分配给第一个文本框,第二个分配给第二个,依此类推。

    【讨论】:

    • 如果 OP 可以使用 Linq,以随机顺序获取字符串就像 var rnd = new Random(); var randomStrings = lst.OrderBy(x =&gt; rnd.Next()); 一样简单——请注意不要在非常紧凑的循环中调用它,因为 Random() 的种子是基于时间,并会导致相同的“随机”序列。如果您想按索引访问项目,您可能还想在OrderBy(...) 之后添加.ToList()
    【解决方案2】:

    您可以使用列表,并且在每次分配后,您可以从列表中删除分配的项目。这样可以防止重复。

    http://msdn.microsoft.com/en-us/library/cd666k3e(v=vs.110).aspx

    【讨论】:

      【解决方案3】:

      选择后删除每个项目怎么样?

      试试类似的东西

       comboBox1.Items.RemoveAt(x);
      

      添加后,每次你的

      x = rnd.Next(0, 16);
      

      代码将缩减为

      x = rnd.Next(0, 15);
      

      直到它达到零。 另一种方法是在随机选择一个遍历所有填充的循环(或所有更简单的代码)并检查它是否已被选择之后。如果已经选择了,则换一个新的,直到它不同为止。

      为此,您可以使用文本框数组(将您拥有的内容存储在数组中)并像这样循环遍历它们

          for(int i=0;i<16;i++)
          if(textBoxArray[i].Text==comboBox2.Items[x].toString()){
          chosen=true;
      }
      

      但是从组合框中删除它们比代码更简单、更快。如果您希望它们仍然出现在您的组合框中,您可以同时在一个列表中,从该列表中获取您的项目并将其从那里删除。 用户不会看到任何东西。

      【讨论】:

        【解决方案4】:

        要做到这一点,相当简单。

        首先,您知道总共有 16 个项目。您不需要随机化列表,而是随机化用于访问列表项的索引。这部分你知道。

        为了避免重复项,你需要保留一个已经使用过的索引列表。一旦确定了未使用的索引,就需要访问您的列表。

        例子:

        class Sample
        {
           List<int> _usedIndexes;
        
           public Sample()
           {
              _usedIndexes = new List<int>();
           }   
        
           public int GetRandomIndex(int s, e)
           {
              Random rnd = new Random();
        
              //Initialize with a random number
              int x = rnd.Next(s, e);
        
              //While the index exists in the list of used indexes, get another random number.
              while(_usedIndexes.Exists(index => index == x))
              {
                 x = rnd.Next(s, e);
              }
        
              //Add the number to the list of used indexes 
              _usedIndexes.Add(x);
        
              return x;
           }
        }
        

        然后您只需使用您获得的索引访问您拥有的名称列表,如下所示:

        int unusedIndex = GetRandomIndex(0, 16);
        
        User1.Text = comboBox2.Items[unusedIndex].ToString();
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-02-19
          相关资源
          最近更新 更多