每次循环运行时更新列表-意外行为
本文关键字:意外 列表 更新 循环 运行时 | 更新日期: 2023-09-27 18:10:30
我试着写一个简单的程序,模拟彩票,我得到了一些我无法理解的行为,也无法修复:
为了简单起见,我排除了与问题无关的代码
程序:点击它应该得到用户输入的6个不同的数字(1到49之间),得到6个不同的随机数(1到49之间)比较它们,重复得到随机数并与输入的比较,直到有3个匹配。
-
什么是相关的,我在按钮单击上调用函数GetResults()并传递给它两个参数(下面的方法定义)。我将其简化为按钮点击向您展示。那里有一些条件和函数调用,但它们正在工作,即使没有它们也存在问题,所以这就是为什么底部的图像示例可能有点不同。
private void btnCheck_Click(object sender, EventArgs e) { lotto.GetResults(3, ref listRndNumLabels); lblMatches.Text = lotto.CurrentMatches.ToString(); lblTryCounter.Text = lotto.NumberOfTries.ToString(); lblBalance.Text = lotto.Balance.ToString() + " zł"; lblThreesAmmount.Text = lotto.ThreesAmmount.ToString(); lblFoursAmmount.Text = lotto.FoursAmmount.ToString(); lblFivesAmmount.Text = lotto.FivesAmmount.ToString(); lblSixesAmmount.Text = lotto.SixesAmmount.ToString(); }
-
方法GetResults()以3作为期望匹配的数量和在末尾更新的标签列表
public void GetResults(int Choice, ref List<Label> listLblRndNum) { _currentMatches = 0; int desiredNumberOfMatches = Choice; // while we got other ammount of matches than three, go again while (_currentMatches != desiredNumberOfMatches) { _numberOfTries++; // get list of mutually exclusive 6 numbers betweeen 1 and 49 var tempList = GetRndNums(); // insert random numbers to list _listLotteryNumbers.Clear(); for (int i = 0; i < 6; i++) { _listLotteryNumbers.Insert(i, tempList[i]); } _balance -= _ticketCost; _currentMatches = 0; // get number of matches for (int i = 0; i < 6; i++) { foreach (int num in _listLotteryNumbers) { if (_listSelectedNumbers[i] == num) { _currentMatches++; } } } //FrmLotto.lbResults.Items.Add(_numberOfTries.ToString() + " - _currentMatches: " + _currentMatches.ToString()); //FrmLotto.lbResults.Items.Add(_numberOfTries.ToString() + " - tempList { " + tempList[0] + " " + tempList[1] + " " + tempList[2] + " " + tempList[3] + " " + tempList[4] + " " + tempList[5] + " }"); //FrmLotto.lbResults.Items.Add(_numberOfTries.ToString() + " - _listLotteryNumbers { " + _listLotteryNumbers[0] + " " + _listLotteryNumbers[1] + " " + _listLotteryNumbers[2] + " " + _listLotteryNumbers[3] + " " + _listLotteryNumbers[4] + " " + _listLotteryNumbers[5] + " }"); //FrmLotto.lbResults.Items.Add(_numberOfTries.ToString() + " - _listSelectedNumbers { " + _listSelectedNumbers[0] + " " + _listSelectedNumbers[1] + " " + _listSelectedNumbers[2] + " " + _listSelectedNumbers[3] + " " + _listSelectedNumbers[4] + " " + _listSelectedNumbers[5] + " }"); // update stats if (_currentMatches == 3) { _threesAmmount++; _balance += 10; } else if (_currentMatches == 4) { _foursAmmount++; _balance += 100; } else if (_currentMatches == 5) { _fivesAmmount++; _balance += 3500; } else if (_currentMatches == 6) { _sixesAmmount++; _balance += 1000000; } //FrmLotto.lbResults.Items.Add(_numberOfTries.ToString() + " - Threes Ammount right after updating: " + _threesAmmount); //FrmLotto.lbResults.Items.Add(""); // this gets out of the loop if user has chosen from ddl to run once, it is irrelevant here if (desiredNumberOfMatches == -1) break; } // finally update Labels with the desired result for (int i = 0; i < 6; i++) { listLblRndNum[i].Text = _listLotteryNumbers[i].ToString(); } }
-
这是得到随机数的函数:
public List<int> GetRndNums() { List<int> listRndNums = new List<int>(); Random rndNum = new Random(); for (int i = 0; i < 6; i++) { int myNum = 0; do myNum = rndNum.Next(1, 49); while (listRndNums.Contains(myNum)); listRndNums.Add(myNum); } listRndNums.Sort(); return listRndNums; }
如果循环只运行一次,或者每次循环后有延迟,或者我在循环中设置了断点,那么程序就会按预期工作。
否则会有一个意想不到的行为,对于相同的数据(对于相同的列表)循环运行不止一次,我不明白为什么。
查看图片:
- 程序运行一次,我点击按钮五次,向您显示结果很好:
(btw = sprawdski = Check, raz = once, do pierwszej trójki = until 3 match)
http://ultraimg.com/jHQY- 当我选择直到3匹配(或点击按钮从上面的代码示例),我收到错误的结果,循环运行多次相同的值。
将非常感谢帮助,我正在学习,我知道代码的许多部分可以改进,许多部分是临时调试的目的。但是这种行为,我实在不明白
为了解决这个问题,你应该尝试制作
Random rndNum = new Random();
一个静态变量。
看这个:http://msdn.microsoft.com/en-us/library/system.random.aspx
伪随机数是以等概率从有限的数集合中选出的。所选的数字不是完全随机的,因为使用了确定的数学算法来选择它们,但对于实际目的来说,它们是足够随机的。Random类的当前实现是基于Donald E. Knuth的减法随机数生成器算法。欲了解更多信息,请参阅d.e.k nuth。计算机程序设计艺术,第二卷:半数值算法。Addison-Wesley, Reading, MA,第二版,1981.
随机数的生成从种子值开始。如果是一样的重复使用种子,生成相同序列的数字。一个产生不同序列的方法是使种子值时间依赖,因此产生不同的系列与每个新的随机的实例。类的无参数构造函数Random类使用系统时钟生成它的种子值,而它的参数化构造函数可以接受一个Int32值当前时间的刻度数。然而,因为时钟已经有限分辨率,使用无参数构造函数创建不同的随机对象紧密连续产生随机数生成相同的随机数序列的生成器。的下面的例子说明了两个随机对象紧密连续的实例化产生一系列相同的随机数。
byte[] bytes1 = new byte[100];
byte[] bytes2 = new byte[100];
Random rnd1 = new Random();
Random rnd2 = new Random();
rnd1.NextBytes(bytes1);
rnd2.NextBytes(bytes2);
Console.WriteLine("First Series:");
for (int ctr = bytes1.GetLowerBound(0);
ctr <= bytes1.GetUpperBound(0);
ctr++) {
Console.Write("{0, 5}", bytes1[ctr]);
if ((ctr + 1) % 10 == 0) Console.WriteLine();
}
Console.WriteLine();
Console.WriteLine("Second Series:");
for (int ctr = bytes2.GetLowerBound(0);
ctr <= bytes2.GetUpperBound(0);
ctr++) {
Console.Write("{0, 5}", bytes2[ctr]);
if ((ctr + 1) % 10 == 0) Console.WriteLine();
}
// The example displays the following output to the console:
// First Series:
// 97 129 149 54 22 208 120 105 68 177
// 113 214 30 172 74 218 116 230 89 18
// 12 112 130 105 116 180 190 200 187 120
// 7 198 233 158 58 51 50 170 98 23
// 21 1 113 74 146 245 34 255 96 24
// 232 255 23 9 167 240 255 44 194 98
// 18 175 173 204 169 171 236 127 114 23
// 167 202 132 65 253 11 254 56 214 127
// 145 191 104 163 143 7 174 224 247 73
// 52 6 231 255 5 101 83 165 160 231
//
// Second Series:
// 97 129 149 54 22 208 120 105 68 177
// 113 214 30 172 74 218 116 230 89 18
// 12 112 130 105 116 180 190 200 187 120
// 7 198 233 158 58 51 50 170 98 23
// 21 1 113 74 146 245 34 255 96 24
// 232 255 23 9 167 240 255 44 194 98
// 18 175 173 204 169 171 236 127 114 23
// 167 202 132 65 253 11 254 56 214 127
// 145 191 104 163 143 7 174 224 247 73
// 52 6 231 255 5 101 83 165 160 231
这个问题可以通过创建一个随机对象来避免而不是多个。为了提高性能,请创建一个Random对象随着时间的推移生成许多随机数,而不是重复地生成创建一个新的随机对象来生成一个随机数。来生成适合于的加密安全随机数例如,创建随机密码时,使用派生的类System.Security.Cryptography.RandomNumberGenerator等System.Security.Cryptography.RNGCryptoServiceProvider .