Why am I getting duplicates? - c#

I've built a Keno game, and it picks 20 random numbers out of an arraylist, NumbersToPickFrom. I generate a random number and then check if that number is currently in the numbers available to pick from. If it is, I add it to my arraylist of numbers that will be used as the lottery numbers, randomPicks, and then I remove it from the available numbers. If it's not in the list, that means it's already been picked, and I need a new number. I use a goto to start over. I thought it was working fine, but it seems I've been getting duplicates. Am I using the ArrayList.Remove function wrong? If it's removed, I shouldn't be getting duplicates in my final listing of random picks. If anybody can see where I missed something, that would be helpful. The below code is just the code involved in what I'm talking about.
private void GeneratePicks()
{
for (int i = 1; i <= 20; )
{
Retry:
int rInt = GenerateRandomPick();
if (NumbersToPickFrom.Contains(rInt))
{
RandomPicks.Add(rInt);
NumbersToPickFrom.Remove(rInt);
i++;
//PickBox.Text += rInt + " ,";
RandomPicks.Sort();
}
else
{
goto Retry;
}
}
}
private int GenerateRandomPick()
{
int rInt = rand.Next(1,81);
return rInt;
}
private void initializeArray()
{
for (int i = 1; i <= 80; i++)
{
NumbersToPickFrom.Add(i);
}
}

I ran your code and didn't get any duplicates at all.
Nevertheless, the approach of repeatedly picking random numbers and comparing to the shrinking list isn't the best way to do this.
Try this instead:
RandomPicks =
Enumerable
.Range(1, 80)
.OrderBy(n => rand.Next())
.Take(20)
.OrderBy(n => n)
.ToList();

I found that your code is working fine.
I added the following public variables to make it work though (on my machine)
List<int> NumbersToPickFrom = new List<int>();
List<int> RandomPicks = new List<int>();
Random rand = new Random();
Though on the second run, i found that the number of items in RandomPicks have doubled and there were duplicates as well, so I changed initializeArray() as below
private void initializeArray()
{
for (int i = 1; i <= 80; i++)
{
NumbersToPickFrom.Add(i);
}
RandomPicks.Clear(); // Added this to clear the existing values in the list.
}

If you want to do it "old school" and actually watch what's happening, change your GeneratePicks() method to this:
private void GeneratePicks()
{
RandomPicks = new List<int>();
initializeArray();
for (int i = 0; i < 20; ++i)
{
int randomIndex = rand.Next(1, 80 - i);
int randomPick = NumbersToPickFrom[randomIndex];
RandomPicks.Add(randomPick);
NumbersToPickFrom[randomIndex] = NumbersToPickFrom[80 - i - 1];
}
RandomPicks.Sort();
}
This will run through exactly 20 times and guarantee non-duplicates.

I can't see any error in your code, and tested your code by running it 100000 times and didn't get any duplicates.
There are however better methods for getting random numbers. One easy improvement would be to randomly pick a number from the NumbersToPickFrom list instead of just picking a number, then you don't need the inner loop.
There is a nicer way to pick lottery numbers. You can loop through the numbers and calculate the probability that each number should be picked. The probability of a number being picked is PicksLeft / NumbersLeft, for example the probability for the number 1 to be picked is 20 / 80, and then the probability changes depending on which numbers are picked:
private void GeneratePicks() {
int pick = 20;
for (int n = 1; pick > 0; n++) {
if (rand.Next(81 - n) < pick) {
RandomPicks.Add(n);
pick--;
}
}
}
As the numbers are picked in order, you don't even have to sort the numbers afterwards, and you don't need the NumbersToPickFrom list.

Related

Way to extract positive and negative numbers from one array to another two (positive and negative)

I'm studying c# and I was wondering if there is any way to extract positive and negative numbers (integers) from one array to others two, one that contains the positive numbers and the other negative ones
I've tried something like
public static void Main(string[] args)
{
int[] num = new int[50];
Random objeto = new Random();
int i = 0;
for (i = 1; i <= 50; i++)
{
Console.WriteLine("Random numbers:");
num[1] = objeto.Next(-50, 50);
Console.WriteLine(num[1] + "");
}
Console.ReadKey(); here
}
I have to create two other arrays
int[] positive_numbers = int new [N]
int[] negative_numbers = int new [N]
And I guess I should create a method, but I do not know how I have to do it.
You could use LINQ:
var positiveNumbers = numbers.Where(n => n > 0).ToArray();
var negativeNumbers = numbers.Where(n => n < 0).ToArray();
Or an alternative approach is to count how many even and odd numbers you have, create two arrays and then populate them. This assumes that you want the arrays to be exactly the correct length.
// Variables to store counts of positive and negative numbers
int positiveCount = 0;
int negativeCount = 0;
// Because we'll be building new arrays, we need to track our
// position within them, so we create two variables to do that
int positiveIndex = 0;
int negativeIndex = 0;
// loop through once to count the positive and negative numbers
foreach (var number in numbers)
{
if (number > 0)
{
++positiveCount; // same as positiveCount = positiveCount + 1
}
else if (number < 0)
{
++negativeCount;
}
}
// now we know how many +ve and -ve numbers we have,
// we can create arrays to store them
var positiveNumbers = new int[positiveCount];
var negativeNumbers = new int[negativeCount];
// loop through and populate our new arrays
foreach (var number in numbers)
{
if (number > 0)
{
positiveNumbers[positiveIndex++] = number;
// number++ will return the value of number before it was incremented,
// so it will first access positiveNumbers[0] and then positiveNumbers[1], etc.
// each time we enter this code block.
}
else if (number < 0)
{
negativeNumbers[negativeIndex++] = number;
}
}
An alternative approach to the initial count would be to define both arrays to be the same length as the numbers array, and then use positiveIndex and negativeIndex to determine the maximum populated index in the positiveNumbers and negativeNumbers arrays. The downside is that it uses a little more memory (but memory is cheap for such a small set), and the upside is that you only have to loop through once so it's more performant.
If your situation allows, it might be easier to use generic lists instead:
var positiveNumbers = new List<int>();
var negativeNumbers = new List<int>();
foreach (var number in numbers)
{
if (number > 0)
{
positiveNumbers.Add(number);
}
else if (number < 0)
{
negativeNumbers.Add(number);
}
}
Generic lists are basically fancy wrappers around internal arrays. The list starts out with an array of a relatively small size. As you add items to the list, more arrays are generated to store all of your items. You can see the current overall size of the internal arrays by checking the list's .Capacity property. Do not confuse Capacity with Count. Count shows the number of items actually in your list, whereas Capacity shows the number of items your list can hold before expanding.
Note that in these answers, zeroes will be excluded since you only asked for positive and negative numbers, and zero is neither. As highlighted by Max Play's comment, you should change > to >= if you consider zero to be positive.
Assuming you'll handle 0 as positive, add a method to check for positive.
private static bool isNegtive(int number)
{
return number < 0;
}
I'd use list over array for unknown quantities. It'd go something like this:
public static void SeparateRandomNumbers()
{
IList<int> positive_numbers = new List<int>();
IList<int> negative_numbers = new List<int>();
Random objeto = new Random();
for (int i = 0; i < 50; i++)
{
var number = objeto.Next(-50, 50);
if (isNegtive(number))
{
negative_numbers.Add(number);
}
else
{
positive_numbers.Add(number);
}
}
}

c# unique random number

i'm trying to get X number of random number (where X is a variable) between 0 and 100 and add them to a row in a DataGridView. I'm using the code below, but the problem is i need it to be impossible to have the same number twice. Is there a way make sure i get unique random numbers?
int X = 20;
Random random = new Random();
int randomrow = random.Next(0, 100);
for (int i = 0; i < X; i++)
{
int randomNumber = random.Next(0, 100);
data.Rows[randomrow][3] = randomNumber;
}
Thanks for the help!
Split your problem in two:
Create a list of X random, unique numbers. There are numerous ways to do that:
a. Create a list of all numbers 0-100 and then shuffle them. OR
b. Keep a hash set of all the numbers you already created (in addition to the list) and only add a new one if it has not been added before.
Afterwards, loop through the list and the data rows simultaneously and insert the values into the rows.
Here's the simple way to do it without creating a shuffle method for the List (though there are examples of that). Basically create a list of all possible integers, populate the list, then sort by new GUIDs.
int X = 20;
var RowNumbers = new List<int>();
for (int i = 0; i < X; i++)
RowNumbers.Add(i);
foreach (int i in RowNumbers.OrderBy(f => Guid.NewGuid()))
{
data.Rows[i][3] = i;
}
You would need to compare the numbers you have already used to the next one you get from random.Next. If you have already used it, pick another. I also like Heinzi's answer.
Here is algorithm without shuffling and previous result using:
var max = 100; // max available value
var count = 20; // number of random numbers
var random = new Random();
var rest = (double)max;
for (int i = 0; i < max; i++, rest--)
{
if (count / rest > random.NextDouble())
{
Console.WriteLine(i); // here is your random value
count--;
if (count == 0)
{
break;
}
}
}

How to generate two random numbers, X and Y, and make sure they are never repeated?

Ok, so I am writing a Minesweeper app in WinForms. This is my first C# app so it has been a huge learning process. I want to randomly generate two numbers to put into two separate arrays, mineX & mineY. These two arrays are the coordinates for where all the mines are going to be placed on the board.
Here is the issue, I want to make sure that when it randomly generates these numbers, that X,Y will never be the same. I've done the research and know how to generate a single number and make each one unique. My issue is I want the combination of two random numbers to be unique.
Here is my code for the placeMines method.
private void placeMines()
{
Random rnd = new Random();
for (int i = 0; i < MINE_COUNT; i++)
{
bombX[i] = rnd.Next(0, BOARD_X);
bombY[i] = rnd.Next(0, BOARD_Y)'
}
}
This seems to be a simple issue to resolve, but I can't figure it out for the life of me.
Create a list of possible mine positions.
Choose a random item from the list, remove the item.
Repeat 2 until there're enough mines.
Sample code:
const int BOARD_X = 10;
const int BOARD_Y = 6;
const int MINE_COUNT = 30;
List<int> positions = Enumerable.Range(0, BOARD_X * BOARD_Y).ToList();
var rnd = new Random();
for (int i = 0; i < MINE_COUNT; i++) {
int index = rnd.Next(positions.Count);
int pos = positions[index];
positions.RemoveAt(index);
int x = pos % BOARD_X, y = pos / BOARD_X;
Console.WriteLine("({0}, {1})", x, y);
}
NOTE: If the number of positions is big, you can optimize algorithm for space by using bit vectors. I'll leave this as an exercise.
Generate all positions (let it be struct with two int fields x, y) in array and shuffle this array.
Random _rand = new Random();
Position[] allPositions = GenerateAllPositions();
for (int i=allPositions.Length-1; i>=1; i--)
{
int j = _rand.Next(0, i+1);
// now swap
Position tempPosition = allPositions[i];
allPositions[i] = allPositions[j];
allPositions[j] = tempPosition;
}
Now you can have temp int variable lastQueriedPositionIndex = 0, increase it by one when you pick any position. If lastQueriedPositionIndex == allPositions.Length make lastQueriedPositionIndex=0 and invoke this "swap" routine again. This is O(n) worst case solution instead of O(n^2) solution proposed by Athari - however in small board dimensions you won't see any diffrence.

Is my lottery program wrong ? or am I so unlucky?

I made a lottery program : http://yadi.sk/d/bBKefn9g4OC7s
Here is the whole source code : 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
}
}
}
This section I'm generating random 6 different numbers between 1-49
Also I'm wondering in this example, are nested loops increase the spontaneity ?
I'm getting 3-4 max, this program wrong or am I so unlucky ?
( note that : that's my first program )
For all guys trying to help me : I'm really beginner on programming(c# yesterday | c++ 3 weeks i guess), and if you guys clarify what you mean in codes it'll be great.
And please not give me extreme hard coding examples( I don't wanna quit c# )
Your method looks unsafe, as get value from Random again in the inner loop does not guarantee that it will return unduplicated value. For low value as 1-49, you can use simple random-picking algorithm like this
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);
}
Note that this is far from optimal solution in terms of performance, but if you will run it only once in a few seconds or more so it should be fine.
I think it's correct except for the for loop declaration: remember that arrays in C# are zero-based. Thus the loop should look like this:
for (int f = 0; f < 7; f++)
or even better:
for (int f = 0; f < loto.Length; f++)
Update: I cannot comment the other answers (too less reputation), thus I have to post it here:
#Dan: only one loop is not correct as it is not allowed to have the same number twice in Loto. In his inner loop, 1342 checks if the created random number already exists, so it is not correct to leave it out.
#James: As 1342 just started programming, it is not necessary to use a static field in my opinion. I guess that he or she has his whole code in the Main method so there is no benefit using a static variable.
There are a few issues here - you've got one too many loops for a start, and no comments.
See this (over-commented) example below:
// 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;
}
}
}
You should end up with a 6 element long array with 6 random numbers between 1 and 50 in it.
Hope that helps!
Edit:
It's also well worth taking note of James' answer - if you're doing the above in a loop, you'll get the same values every time from Random, due to how the seed is used. Using a static version of Random will give much better results.
You don't want to keep re-creating a new instance of Random each time, that's the likely cause of why you keep getting similar values each time. The better approach is to create a static instance of Random and use that across your entire app - this should give you more realistic results e.g.
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);
For easily testing it, I have left the console logs and static void main for you.
You do not need two iterations for this. Also - arrays are 0 based, so either f has to be equal to 0, or less than 7. I went with equal 0 below.
I have created a recursive method which creates a new value and checks if the array contains the value. If it does not contain it, it adds it. But if it does contain it, the method calls itself to find a new value. It will continue to do this until a new value is found.
Recursive methods are methods which call themselves. Don't try and fill an array with an index bigger than 50 with this, as you will get an endless loop.
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);
}
I can see that you are trying to simulate drawing 6 lottery numbers between 1 and 50.
Your code has some logic errors, but rather than fixing it I'm going to suggest doing it a different way.
There are several ways to approach this; a common one is this:
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
But there's another approach which scales nicely, so I'll demonstrate this one (someone else will probably already have written about the other approach):
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
This is pretty much what happens in a real-life lottery.
To shuffle a collection we can use the Fisher-Yates Shuffle. Here's an implementation:
/// <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();
}
Here's a full compilable example. I've avoided using Linq in this example because I don't want to confuse you!
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();
}
}

How do you make an array of 1000 random integers between 1-100

How do you program c# to make an array of 1000 random integers between 1-100.
And then how do you get when a person enters a number e.g. 68 how can you make the program say 68 appears so and so many times or that it doesn't work at all!
I am not asking for the complete answer I just need a hint where to get started.
Here is what I know:
I have to use the random function and an if but I dont know what to put where!
int[] iArray = new int[1000];
int counter = 0;
Random random = new Random();
for(int i = 0; i < 1000; i++){
iArray[i] = random.Next(1, 101); //1 - 100, including 100
}
int number = Convert.ToInt32(Console.ReadLine());
foreach(int i in iArray){
if(i == number)count++;
}
Console.WriteLine("The number "+ number+" appears "+count+" times!");
Start with a for loop, in each iterative you call the random function and put the result in a public list. After that you make an dialog for the user to type a number. You can serach with lambda expression in the list to see how many matches you get.
Make an array of 1000 random integers between 1-100 and when a person enters a number e.g. 68 how can you make the program say 68 appears so and so many times
I think you're looking for a method like this:
private static Random rnd = new Random();
public static IEnumerable<int> getRandomNumbers(int count, int lowerbound, int upperbound, int specialNumber = int.MinValue, int specialNumberCount = int.MinValue)
{
List<int> list = new List<int>(count);
HashSet<int> specialNumPositions = new HashSet<int>();
if (specialNumberCount > 0)
{
// generate random positions for the number that must be create at least n-times
for (int i = 0; i < specialNumberCount; i++)
{
while (!specialNumPositions.Add(rnd.Next(0, count)))
;
}
}
while (list.Count < count)
{
if (specialNumPositions.Contains(list.Count))
list.Add(specialNumber);
else
list.Add(rnd.Next(lowerbound, upperbound + 1));
}
return list;
}
which you can use in this way:
// ensure that 68 is generated at least 10 times
var list = getRandomNumbers(1000, 1, 100, 68, 10);
Demo
If you instead just want to know how often a number appears in the list, you can ue Linq:
int count = list.Count(i => i == 68);

Categories