【问题标题】:How to pick a random string from string array only once如何仅从字符串数组中选择随机字符串一次
【发布时间】:2014-04-03 00:26:42
【问题描述】:

我正在尝试用 C# 制作 Hangman,在游戏开始时你需要一个单词来猜测,所以游戏不会很无聊你可以得到很多单词(一次只能一个)。但是当你开始一个新游戏时,你不会得到一个你已经猜到的词。所以我必须选择一个我还没有选择的随机字符串。

我尝试了多种方法来解决这个问题,但都没有成功。

方法#1:

在这里我运行 NewWord 函数,然后将 numberOfTries 加 1。

string[] wordArr = { "PROGRAMMERING", "CSHARP", "STOL", "ELEV", "VISUAL", "STUDIO" };
int numberOfTries = 0;
int randomNumber = -1;


protected string NewWord()
{
    if (!(numberOfTries >= wordArr.Length))
    {
        randomNumber = RandomNumberFromTo(0, (wordArr.Length - numberOfTries));

        ChangeWord(((wordArr.Length - numberOfTries)-1), randomNumber);

        return wordArr[(randomNumberl)];
    }
    else
    {
        return "There are no more new words!! :(";
    }
}


private int RandomNumberFromTo(int NumberA, int NumberB)
{
    System.Threading.Thread.Sleep(2);
    Random minRandomGenerator = new Random();
    System.Threading.Thread.Sleep(3);
    return minRandomGenerator.Next(NumberA, NumberB);
}



protected void ChangeWord (int NumberA, int NumberB)
{
    string cashe1 = wordArr[NumberA];
    wordArr[NumberA] = wordArr[NumberB];
    wordArr[NumberB] = cashe1;
    return;
}

我在 StackOverflow 上找到了方法 #2,但它不起作用。

这里我也运行 NewWord 函数,然后将 numberOfTries 加 1。

string[] wordArr = { "PROGRAMMERING", "CSHARP", "STOL", "ELEV", "VISUAL", "STUDIO" };       
int numberOfTries = 0;
Random random = new Random();
protected string NyttOrd()
{
    if (!(numberOfTries >= wordArr.Length))
    {
        var names = new List<string> { "PROGRAMMERING", "CSHARP", "STOL", "ELEV", "VISUAL", "STUDIO" };

        System.Threading.Thread.Sleep(3);
        int index = random.Next(names.Count);
        var name = names[index];
        names.RemoveAt(index);
        return name;
    }
    else
    {
        return "There are no more new words!! :(";
    }
}

我还尝试了一个版本,其中有两个不同的数组,一个是 Int-Array,第二个是 String-Array。真的很乱,没有用。

我对 C# 也很陌生,我只知道基础知识,例如 +-/*、转换、函数和数组。

【问题讨论】:

  • Non-repetitive random number C# 的可能重复项
  • 很难遵循方法中的差异,但不要在方法中声明 Random 类。只需在整个代码中使用单个实例。
  • Pierre-Luc,他要求相同的方法,但要求 Int 不是字符串。磅。抱歉代码乱七八糟...会移动随机类:)
  • 我已经编辑了你的标题。请参阅“Should questions include “tags” in their titles?”,其中的共识是“不,他们不应该”。
  • 好的,谢谢,我会记住的! :)

标签: c# arrays string random combinations


【解决方案1】:
static readonly List<string> Words = new List<string>(wordArr);
static readonly Random Rnd = new Random();

public string Next()
{
    if(Words.Count < 1)
        return "There are no more new words!! :(";

    var index = Rnd.Next(0, Words.Length);
    var result = Words[index];
    Words.RemoveAt(index);

    return result;
}

【讨论】:

  • Random.Next 有奇怪的语义。第二个参数比您需要的上限高一个。所以你的电话应该是Rnd.Next(0, Words.Length) 没有` - 1`。
  • 另外,这段代码如何跟踪已经使用的单词?
  • 不保留用过的词,从集合中删除用过的词,如果你需要知道用过的词,那么 wordArr.Except(Words) 就足够了。
  • 删除所有使用过的单词后,我不需要跟踪我已经使用过哪些单词。我可以用一个简单的 Int Counter 记录我使用了多少次尝试 :)
  • @TolgahanAlbayrak - 很抱歉 - 我错过了您代码中的 RemoveAt。我想我需要多睡一会儿。 :-)
【解决方案2】:

从概念上讲,您要么跟踪已使用的字符串,要么在使用时从可选字符串列表中删除字符串。

要实现第一种方法,您可以保留一个您已经使用过的字符串的哈希表,并在拉取一个新字符串时 - 查看它是否存在于哈希表中(如果存在,请选择另一个,直到“新鲜" 字符串被选中)。

要实现第二种方法,只需在您选择它们​​时从列表中删除您选择的字符串。

【讨论】:

  • 在第二种方法中,已选择的字符串将被删除:“names.RemoveAt(index);”。但是当我多次运行时,我仍然会得到重复...
【解决方案3】:

使用KeyValuePair。

键是你的单词,值是它被使用的次数,然后只取最少使用的单词并增加它的计数器。

List<KeyValuePair<string, int>>

【讨论】:

  • 是的,同样的事情。 :P 我只使用 List 是因为他已经在使用它了。
【解决方案4】:

如果你打乱你的单词数组:

var r = new Random();
var shuffledWords = wordArr.OrderBy(_ => r.Next());

然后将你的单词压入堆栈:

var wordStack = new Stack<string>(shuffledWords);

现在您有了一个结构,可以将随机单词从集合中交给您,同时使用Stack&lt;T&gt; 的Pop 方法将其从集合中删除(比从@ 的前面/中间删除项目效率更高) 987654325@,虽然你的收藏太少了,但没关系)。

var someWord = wordStack.Pop();

【讨论】:

    【解决方案5】:

    既然你说你是编程新手,那我就快速解释一下重点:

    .Except() 将您的数组与另一个数组进行比较并仅返回唯一元素。 .OrderBy(x => rn.Next()) 将以随机顺序返回数组。 .FirstOrDefault() 将从数组中获取第一个条目,如果数组为空,则返回 null。

    public void GenerateWord()
    {
        Random rn = new Random();
        string[] attemptedWords = LoadUsedWords();
        string[] wordArr = { "PROGRAMMERING", "CSHARP", "STOL", "ELEV", "VISUAL", "STUDIO" };
        string word = wordArr.Except(attemptedWords).OrderBy(x => rn.Next()).FirstOrDefault();
        if (string.IsNullOrEmpty(word))
        {
            Console.WriteLine("Oh no");
        }
        else
        {
            Console.WriteLine(word);
        }
    }
    
    public string[] LoadUsedWords()
    {
        return new string[] { "PROGRAMMERING", "CSHARP", "STOL", "ELEV", "VISUAL" };
    }
    

    【讨论】:

      【解决方案6】:

      您应该将您的WordArr 表示为一个列表。它更容易满足您的需求。

      这是一种随机化列表的简单方法:

      List<string> wordArr = new List<string>()
      {
          "PROGRAMMERING", "CSHARP", "STOL", "ELEV", "VISUAL", "STUDIO"
      };
      Random random = new Random();
      wordArr = wordArr.OrderBy(x => random.Next()).ToList();
      

      然后总是取列表中的第一个单词,这样你就可以像这样简单地删除你使用的每个单词:

      wordArr.RemoveAt(0);
      

      当wordArr 为空时,您就完成了。

      【讨论】:

        猜你喜欢
        • 2020-10-04
        • 2014-02-03
        • 1970-01-01
        • 2015-09-19
        • 1970-01-01
        • 1970-01-01
        • 2017-01-12
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多