我的彩票计划错了吗?还是我太不幸了
本文关键字:计划 彩票 错了 我的 | 更新日期: 2023-09-27 18:11:03
我做了一个彩票程序:http://yadi.sk/d/bBKefn9g4OC7s
完整的源代码:http://yadi.sk/d/rnQMfrry4O8cu
Random rnd = new Random();
int[] loto;
loto = new int[7];
for (int f = 1; f <= 6; f++) {
loto[f] = rnd.Next(1, 50); // Generating random number between 1-49
for (int h = 1; h < f; h++) {
if (loto[f] == loto[h]) { // Check with other numbers for the case of duplicate
loto[f] = rnd.Next(1, 50); // If there is a duplicate create that number again
}
}
}
这一节我将在1-49之间随机生成6个不同的数字
我还想知道在这个例子中,嵌套循环是否增加了自发性?
我得到3-4个最大值,这个程序错了,还是我太不幸了?
(注意:这是我的第一个程序)
对于所有试图帮助我的人:我真的是编程初学者(c#昨天| c++ 3周我猜),如果你们在代码中澄清你的意思,那将是伟大的。请不要给我极端硬编码的例子(我不想退出c#)
您的方法看起来不安全,因为在内部循环中再次从Random
获取值并不能保证它将返回不可重复的值。对于1-49这样的低值,您可以使用如下的简单随机选择算法
var numbers = new List<int>();
for (int i = 1; i <= 49; i++) {
numbers.Add(i);
}
Random r = new Random();
var loto = new int[6];
for (int f = 0; f < 6; f++) {
int idx = r.Next(0, numbers.Count);
loto[f] = numbers[idx];
numbers.RemoveAt(idx);
}
请注意,就性能而言,这远非最佳解决方案,但如果您只在几秒钟或更长时间内运行一次,那么它应该没问题。
我认为这是正确的,除了for循环声明:记住,c#中的数组是从零开始的。因此循环应该是这样的:
for (int f = 0; f < 7; f++)
或者更好:
for (int f = 0; f < loto.Length; f++)
更新:我无法评论其他答案(太不信誉),因此我不得不在这里发布:
@Dan:只有一个循环是不正确的,因为在Loto中不允许有相同的数字两次。在他的内部循环中,1342检查创建的随机数是否已经存在,因此忽略它是不正确的。
@James:由于1342刚刚开始编程,在我看来没有必要使用静态字段。我猜他或她在Main
方法中有他的整个代码,所以使用静态变量没有任何好处。
这里有几个问题-您在开始时使用了太多的循环,并且没有注释。
请看下面这个(过度注释)示例:
// This is static so we don't recreate it every time.
private static Random _rnd;
static void Main(string[] args)
{
_rnd = new Random();
// You can declare and initialise a variable in one statement.
// In this case you want the array size to be 6, not 7!
Int32[] lotoNumbers = new Int32[6];
// Generate 10 sets of 6 random numbers
for (int i = 0; i < 10; i++)
{
// Use a meaningful name for your iteration variable
// In this case I used 'idx' as in 'index'
// Arrays in c# are 0-based, so your lotto array has
// 6 elements - [0] to [5]
for (Int32 idx = 0; idx < 6; idx++)
{
// Keep looping until we have a unique number
int proposedNumber;
do
{
proposedNumber = _rnd.Next(1, 50);
} while (lotoNumbers.Contains(proposedNumber));
// Assign the unique proposed number to your array
lotoNumbers[idx] = proposedNumber;
}
}
}
你最终应该得到一个6个元素的长数组,其中包含6个1到50之间的随机数。希望这对你有帮助!
编辑:同样值得注意的是James的回答——如果你在循环中执行上述操作,由于种子的使用方式,你每次都会从Random获得相同的值。使用静态版本的Random会得到更好的结果。
您不希望每次都重新创建Random
的新实例,这可能是每次都获得相似值的原因。更好的方法是创建Random
的static
实例,并在整个应用程序中使用它-这应该会给你更真实的结果,例如
using System.Collections.Generic;
using System.Linq;
...
static readonly Random rand = new Random();
...
List<int> lottoNumbers = new List<int>(6);
int drawnNumber = -1;
for (int i = 0; i < lottoNumbers.Count; i++) {
do
{
drawnNumber = rand.Next(1, 50); // generate random number
}
while (lottoNumbers.Contains(drawnNumber)) // keep generating random numbers until we get one which hasn't already been drawn
lottoNumbers[i] = drawnNumber; // set the lotto number
}
// print results
foreach (var n in lottoNumbers)
Console.WriteLine(n);
为了便于测试,我为您保留了控制台日志和静态void main。
您不需要为此进行两次迭代。另外,数组是从0开始的,所以f要么等于0,要么小于7。
我创建了一个递归方法,它创建一个新值并检查数组是否包含值。如果它不包含它,它将添加它。但如果它确实包含它,则该方法调用自身来查找新值。它将继续这样做,直到找到一个新值。
递归方法是调用自己的方法。不要尝试用this来填充索引大于50的数组,因为你会得到一个无限循环。
private static readonly Random Rnd = new Random();
static void Main(string[] args)
{
var loto = new int[7];
for (int f = 0; f <= 6; f++)
{
var randomValue = GetRandomNumberNotInArr(loto);
Console.WriteLine(randomValue);
loto[f] = randomValue;
}
Console.Read();
}
/// <summary>
/// Finds a new random value to insert into arr. If arr already contains this another
///random value will be found.
/// </summary>
/// <param name="arr">arr with already found values</param>
/// <returns></returns>
private static int GetRandomNumberNotInArr(int[] arr)
{
var next = Rnd.Next(1, 50);
return !arr.Contains(next) ? next : GetRandomNumberNotInArr(arr);
}
我可以看出您正在尝试模拟抽1到50之间的6个彩票号码。
你的代码有一些逻辑错误,但与其修复它,我建议用另一种方式来做。
有几种方法可以做到这一点;一个常见的例子是:
Create an empty collection of numbers.
while there aren't enough numbers in the collection
let randomNumber = new random number in the appropriate range
if (randomNumber isn't already in the collection)
add randomNumber to the collection
但是还有另一种方法可以很好地扩展,所以我将演示这一种(其他人可能已经写过另一种方法):
Add to a collection all the numbers you want to choose from
Randomly rearrange (shuffle) the numbers in the collection
Draw the required number of items from the collection
这和现实生活中的彩票差不多。
要对集合进行洗牌,我们可以使用Fisher-Yates洗牌。下面是一个实现:
/// <summary>Used to shuffle collections.</summary>
public class Shuffler
{
/// <summary>Shuffles the specified array.</summary>
/// <typeparam name="T">The type of the array elements.</typeparam>
/// <param name="array">The array to shuffle.</param>
public void Shuffle<T>(IList<T> array)
{
for (int n = array.Count; n > 1;)
{
int k = _rng.Next(n);
--n;
T temp = array[n];
array[n] = array[k];
array[k] = temp;
}
}
private readonly Random _rng = new Random();
}
下面是一个完整的可编译示例。我避免在这个例子中使用Linq,因为我不想让你感到困惑!
using System;
using System.Collections.Generic;
namespace Demo
{
public static class Program
{
private static void Main()
{
int[] lotoDraw = createDraw();
Shuffler shuffler = new Shuffler();
shuffler.Shuffle(lotoDraw); // Now they are randomly ordered.
// We want 6 numbers, so we just draw the first 6:
int[] loto = draw(lotoDraw, 6);
// Print them out;
foreach (int ball in loto)
Console.WriteLine(ball);
}
private static int[] draw(int[] bag, int n) // Draws the first n items
{ // from the bag
int[] result = new int[n];
for (int i = 0; i < n; ++i)
result[i] = bag[i];
return result;
}
private static int[] createDraw() // Creates a collection of numbers
{ // from 1..50 to draw from.
int[] result = new int[50];
for (int i = 0; i < 50; ++i)
result[i] = i + 1;
return result;
}
}
public class Shuffler
{
public void Shuffle<T>(IList<T> list)
{
for (int n = list.Count; n > 1; )
{
int k = _rng.Next(n);
--n;
T temp = list[n];
list[n] = list[k];
list[k] = temp;
}
}
private readonly Random _rng = new Random();
}
}