【问题标题】:Check that all values of an array have been used检查是否已使用数组的所有值
【发布时间】:2011-11-15 18:48:43
【问题描述】:

对不起,如果这是一个愚蠢的菜鸟问题。我正在为我的女朋友做一个非常小的项目 - 一个国家列表,她必须输入他们的首都(不起眼的国家,请注意)。由于我是一个完全的初学者,我不得不求助于使用两个数组,一个用于国家,另一个用于首都,并具有匹配的索引。这样就很容易检查正确的答案,而且我不必解析任何文本文件或使用任何数据库。我正在使用随机数使其更有趣。为了阻止程序一遍又一遍地生成相同的国家/地区,我使用了一个整数列表来跟踪已使用的索引,并在列表包含前一个索引时重新生成数字。很基本的东西。令人惊讶的是,这一切都有效。

但是我遇到了问题。基本上,我如何检查我已经用完了国家? :) 我不能简单地对照我的国家/地区数组检查列表大小,因为列表可能包含比数组更多的值,并且 if (taken.Equals(Countries.Length)) 似乎不起作用。或者我在代码中找不到正确的位置来放置这个检查。

很抱歉,这很简单,但我似乎找不到合适的解决方案。

编辑 哇,多么神奇的社区。在从星巴克到我家的短暂步行中,我得到了几十个涵盖大量设计技术的高质量答案。这太棒了!谢谢大家!显然,问题已得到解答,但如果有人有任何额外的 cmets,我会为您发布代码。

// 现在只是一个测试,13 个国家/地区

string[] Countries = {"Belgium", "France", "The Netherlands", "Spain", "Monaco", "Belarus", "Germany",
                             "Portugal", "Ukraine", "Russia", "Sweden", "Denmark", "South Africa"};
        string[] Capitals = {"Brussels", "Paris", "Amsterdam", "Madrid", "Monaco", "Minsk", "Berlin",
                            "Lisbon", "Kiev", "Moscow", "Stockholm", "Copenhagen", "Pretoria"};
        Random number = new Random();
        List<int> taken = new List<int>();
        int index;
        int score = 0;

        private int Generate()
        {

            while (true) {
                index = number.Next(0, Countries.Length);
                if (taken.Contains(index)) continue;
                // THIS IS WHAT I WAS INITIALLY TRYING TO DO
                if (taken.Equals(Countries.Length)) { 
                    MessageBox.Show("Game over!");
                    return -1;


                }
                return index;
            }
        }


        private void Form1_Load(object sender, EventArgs e)
        {
            index = Generate();
            taken.Add(index);
            label1.Text = Countries[index];
            label3.Text = "0 out of " + Countries.Length.ToString();

        }

        private void button1_Click(object sender, EventArgs e)
        {
            if (textBox1.Text.Trim() == Capitals[index].ToString()) {
                label2.Text = "You win!";
                index = Generate();
                taken.Add(index);
                label1.Text = Countries[index];
                textBox1.Clear();
                label3.Text = ++score + " out of " + Countries.Length.ToString();

            }
            else {
                label2.Text = "Wrong!";
                textBox1.Clear();
            }
        }
    }
}

【问题讨论】:

  • List 怎么能比数组包含更多的值?
  • 那么,您只是想创建一个国家/首都对的随机排列以供回答?
  • 好吧,也许不是,这可能是我的夸大其词,但我仍然找不到正确的方法来检查它们的长度是否相等以及将我的代码放在哪里。目前程序只是在我得到最后一个答案时冻结。
  • 这里没有答案。只是想提一下,我在 9 年前为我的女朋友编写了这个 exact 程序。
  • 只是我添加了代码的更新。还必须承认,我使用 List 表示“采取”只是因为它有一个 Add() 方法,而数组没有......

标签: c# arrays list


【解决方案1】:

为了阻止程序一遍又一遍地生成相同的国家/地区,我使用整数列表来跟踪已使用的索引,如果列表包含前一个索引,则重新生成数字。

...

基本上,我如何检查我是否已用完所有国家/地区?

您可能需要考虑另一种方法,因为这将非常昂贵且过于复杂。

您无需尝试随机添加一个国家/地区,而是检查您已添加的国家/地区,您可以制作整个国家/地区列表,然后在集合中添加perform a shuffle(“随机排序”)。这样一来,您就可以按随机顺序一次性获取所有国家/地区。

【讨论】:

  • 好的,我可能会完全重写程序以使用这里提供的所有建议,因为显然我的代码不是惯用的,至少可以这么说。但是您能否查看我发布的代码并告诉我为什么程序在到达最后一个答案时冻结?我什至试图通过检查 Country.Length 的“分数”变量来解决问题,这应该有效,但无效。很抱歉,我将它发布在 cmets 中,我不知道如何在不编辑我最初的帖子的情况下添加正确的帖子。
【解决方案2】:

我们不使用两个数组,或者一个数组和一个列表,而是介绍 C# 4.0 中的一些东西,它实际上看起来很容易使用,并且似乎是为这种类型的赋值而制作的。

仔细观察这段代码,具体看看这些“匿名类型”到底是如何使用的。它让生活变得非常轻松。

// initialize your array like so,
// now you can access your items as countries[1].name and countries[1].city
// and you will never have to worry about having too much cities or countries
// PLUS: they're always together!
var countries =  new [] {
    new { name = "The Netherlands", city = "Amsterdam"},
    new { name = "Andorra",         city = "Vaduz" }, 
    new { name = "Madagascar",      city = "Antananarivo"} 
};

// randomize by shuffling (see http://stackoverflow.com/questions/375351/most-efficient-way-to-randomly-sort-shuffle-a-list-of-integers-in-c-sharp/375446#375446)
Random random = new Random();
for (int i = 0; i < countries.Length; i += 1)
{
    int swapIndex = random.Next(i, countries.Length);
    if (swapIndex != i)
    {
        var temp = countries[i];
        countries[i] = countries[swapIndex];
        countries[swapIndex] = temp;
    }
}

// go through all your items in the array using foreach
// so you don't have to worry about having too much items
foreach(var item in countries)
{
     // show your girlfriend the country, something like
     string inputString = DisplayCountry(item.country);
     if(inputString == item.city)
     {
          ShowMessage("we are happy, you guessed right!");
     }
}


// at the end of the foreach-loop you've automatically run out of countries
DisplayScore(to-your-girlfriend);

注意:您可以轻松地扩展这种匿名类型,方法是添加该特定国家/城市对是否被猜对,然后用她失败的人进行后续测试。

【讨论】:

    【解决方案3】:

    您可以使用HashSet&lt;int&gt; 来跟踪已使用的索引。这不会接受重复的值。 Add 方法返回一个布尔值,指示该值是否已经在列表中:

    if (hashSet.Add(index))
        DisplayValue(index);
    else
        //regenerate
    

    但我可能会使用您现有的策略,但反过来:创建一个预先填充从 0 到 Count - 1 的值的列表。从该列表中选择索引,在使用它们时将其删除。这在逻辑上类似于 Reed Copsey 的排序建议,但可能需要对现有代码进行较少的更改。

    var availableIndexes = new List<int>(Enumerable.Range(0, countryCount));
    var random = new Random();
    while (availableIndexes.Count > 0)
    {
        var index = availableIndexes[Random.Next(0, availableIndexes.Count)];
        DisplayValue(index);
        availableIndexes.Remove(index);
    }
    

    【讨论】:

      【解决方案4】:

      您可以使用键/值对,例如 Dictionary&lt;string, string&gt; 来存储您的国家和首都。然后使用随机 LINQ orderby 子句遍历集合:

      Dictionary<string, string> Countries = new Dictionary<int, string>();
      // populate your collection of countries
      foreach(var country in Countries.OrderBy(c => Guid.NewGuid()))
      {
          Console.WriteLine("Key: {0}  Value: {1}", country.Key, country.Value);
      }
      

      【讨论】:

        【解决方案5】:

        创建一个 Country 类和一个 Capital 类。

        然后为您的类建模以使用 Dictionary&lt;TKey, TValue&gt; 通用集合,以便您将通用 Dictionary 对象声明为:

        Dictionary<Country, Capital>
        

        其中 Country 是关键,Capital 是它的值。

        有关 MSDN 对 Dictionary 的参考及其示例用法,您可以点击以下链接:

        http://msdn.microsoft.com/en-us/library/xfhwa508.aspx

        当您继续使用 Country 和 Capitals 时,请在 Dictionary 实例中检查它们是否存在后将它们添加到上述 Dictionary 实例中,如果它们中的任何一个确实存在,则弹出信息消息或警告。

        【讨论】:

          【解决方案6】:

          快速而肮脏,不一定高效或安全。

          Dictionary<string, string> countriesAndCapitals = new Dictionary<string, string>()
          {
              { "Afghanistan", "Kabul" },
              { "Albania", "Tirane" },
              { "Algeria","Algers" },
              { "Andorra", "Andorra la Vella" } //etc, etc
          };
          
          foreach (var countryCapital in countriesAndCapitals.OrderBy(f => Guid.NewGuid()))
          {
              Console.WriteLine(countryCapital.Key + " " + countryCapital.Value);
          }
          

          【讨论】:

            【解决方案7】:

            看起来你需要的是一种不同类型的数据结构,两组列表可以正常工作,但它很复杂。我建议查看字典列表类型。

            Dictionary<string,string> countryList = new Dictionary<string,string>();
            countryList.Add("Canada","Ottawa");
            countryList.Add("Thailand","Bankok");
            

            等等……

            然后您可以在一个布尔值查看是否有命中时遍历列表。有关Dictionary list type 的更多信息。

            【讨论】:

              【解决方案8】:

              为什么不从您使用的列表中删除这些项目?那么你就没有冲突了。然后你检查 states.Count() > 0.

              【讨论】:

                【解决方案9】:

                我能想到的最快的事情是在您的列表中使用 Distinct() 调用。然后可以将列表中的项目计数与数组的计数进行比较,以查看是否都已使用。

                if(myUsedList.Distinct().Count() < myArray.Count) { ... }
                

                【讨论】:

                  猜你喜欢
                  • 2013-01-27
                  • 2014-08-11
                  • 2012-05-20
                  • 2023-02-05
                  • 2015-06-18
                  • 1970-01-01
                  • 2021-01-07
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多