List of numbers without repetition [duplicate] - c#

This question already has answers here:
How to make this code work without repeating the numbers? [duplicate]
(3 answers)
Closed 4 years ago.
I need to print random numbers from 1 to 99 without repeating them.
The following code gives me stack overflow.
int newNumb= Random.Range(1, 99);
if(acum.Count > 0)
{
while (acum.Contains(newNumb))
{
newNumb= Random.Range(1, 99);
}
}

The typical solution to this problem is to generate the sequential ordered range from 1 to 99 and then shuffle it:
static Random _random = new Random();
public static void Shuffle<T>(IList<T> items)
{
for (int i = thisList.Count - 1; i > 0; i--)
{
int j = _random.Next(0, i);
T tmp = items[i];
items[i] = items[j];
items[j] = tmp;
}
}
var numbers = Enumerable.Range(1,99).ToList();
Shuffle(numbers);
foreach (var number in numbers)
{
Console.WriteLine(number);
}

This will generate a list of random integers, each time a different one, and add it to a list.
The shuffle method is better, but since the range is so limited, also discarding duplicate numbers could work.
Over 100 runs, measuring the elapsed time with a StopWatch(), the list generation never went over 200 Ticks.
The shuffled list 5x times (1029~1395 Ticks) on my machine.
If the list count is set to a value > then the upper range limit (100+ in this case), the the generation procedure will of course never end. There are not enough distinct random values to fill the list.
Random random = new Random();
List<int> acum = new List<int>();
while (acum.Count < 99)
{
int Number = random.Next(1, 100);
if (!acum.Contains(Number))
{
acum.Add(Number);
}
}
To verify the result, order the list and see that it's ordered from 1 to 99:
List<int> acum2 = acum.OrderBy(n => n).ToList();

the best way to do this would be to generate all the necessary numbers, and pull from that list until its empty, creating a new order; this is commonly known as shuffling.
your current code takes way too long, you need to track which numbers have been chosen, and only choose from the remaining ones. in psudocode
generate list
while list not empty
choose number from list
remove it from list
add to new list

Do this simply:
var list = new List<int>();
for (int i = 0; i < 99; i++)
{
list.Add(i);
}
var resultList = list.OrderBy(i => Guid.NewGuid());
Or as suggested by #Camilo:
var resultList = Enumerable
.Range(0, 99)
.OrderBy(i => Guid.NewGuid());
UPDATE
This solution seems to be inefficient. Please use fischer-yates shuffle (shown in #Joel's answer).

Non efficient way (see comments):
Random rand = new Random();
HashSet<int> randomHashSet = new HashSet<int>();
while (randomHashSet.Count < 99)
randomHashSet.Add(rand.Next(1, 100));
List<int> randomList = randomHashSet.ToList();
Update
Efficient way:
Random r = new Random();
var result = Enumerable.Range(1, 99).ToList();
for (int i = 0, j = r.Next(0, 99); i < 99; i++, j = r.Next(0, 99))
result[i] = result[i] + result[j] - (result[j] = result[i]); // Swap

Related

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 unique random integers that do not duplicate

I have created a short program that creates 3 random integers between 1-9 and stores them in an array, however, I would not like any of them to repeat, that is, I would like each to be unique. Is there an easier way to generate 3 unique integers other than having to iterate through the array and comparing each integer to each other? That just seems so tedious if I were to increase my array to beyond 3 integers.
This is my code to generate 3 random numbers. I saw other code in Java, but I thought maybe C# has a easier and more efficient way to do it.
var number = new Numbers[3];
Random r = new Random();
for ( int i = 0; i < number.Length; i++)
{
number[i] = new Numbers(r.Next(1,9));
}
Console.WriteLine("The Three Random Numbers Are:");
foreach(Numbers num in number)
{
Console.WriteLine("{0}", num.Number);
}
I would do something like this:
var range = Enumerable.Range(1, 8);
var rnd = new Random();
var listInts = range.OrderBy(i => rnd.Next()).Take(3).ToList();
You could make an array or a list of the numbers that might be generated, e.g. 0, 1, 2, 3. Then you generate a number from 0 to this list's length, e.g. 2 and pick list[2] so for the next time you only have 0, 1, 3 in your list.
It takes longer to generate it, especially for long lists but it doesn't repeat numbers.
using System;
using System.Collections.Generic;
public class Test
{
static Random random = new Random();
public static List<int> GenerateRandom(int count)
{
// generate count random values.
HashSet<int> candidates = new HashSet<int>();
// top will overflow to Int32.MinValue at the end of the loop
for (Int32 top = Int32.MaxValue - count + 1; top > 0; top++)
{
// May strike a duplicate.
if (!candidates.Add(random.Next(top))) {
candidates.Add(top);
}
}
// load them in to a list.
List<int> result = new List<int>();
result.AddRange(candidates);
// shuffle the results:
int i = result.Count;
while (i > 1)
{
i--;
int k = random.Next(i + 1);
int value = result[k];
result[k] = result[i];
result[i] = value;
}
return result;
}
public static void Main()
{
List<int> vals = GenerateRandom(10);
Console.WriteLine("Result: " + vals.Count);
vals.ForEach(Console.WriteLine);
}
}
Grate explanation and answers from here
Source http://ideone.com/Zjpzdh

How do I check for duplicates in my array?

How do I store a random number into my array, but only if there is not a duplicate already inside the array? My code below still inputs a duplicate number.
Random rand = new Random();
int[] lotto = new int [6];
for (int i = 0; i < lotto.Length; i++)
{
int temp = rand.Next(1, 10);
while (!(lotto.Contains(temp)))//While my lotto array doesn't contain a duplicate
{
lotto[i] = rand.Next(1, 10);//Add a new number into the array
}
Console.WriteLine(lotto[i]+1);
}
Try this:
Random rand = new Random();
int[] lotto = new int[6];
for (int i = 0; i < lotto.Length; i++)
{
int temp = rand.Next(1, 10);
// Loop until array doesn't contain temp
while (lotto.Contains(temp))
{
temp = rand.Next(1, 10);
}
lotto[i] = temp;
Console.WriteLine(lotto[i] + 1);
}
This way the code keeps generating a number until it finds one that isn't in the array, assigns it and moves on.
There are a lot of ways to 'shuffle' an array, but hopefully this clears up the issue you were having with your code.
What you really want is to shuffle the numbers from 1 to 9 (at least that's what your example is implying) and then take the first 6 elements. Checking for duplicates is adding unnecessary indeterminism and really is not needed if you have a shuffle.
E.g take this accepted answer for a Fisher-Yates shuffle and then take the first 6 elements for lotto.
This would then look like this:
lotto = Enumerable.Range(1,9)
.Shuffle()
.Take(6)
.ToArray();

C# - Writing numbers 1 through 10 in random order [duplicate]

This question already has answers here:
Is using Random and OrderBy a good shuffle algorithm? [closed]
(13 answers)
Closed 9 years ago.
Part 1: All I am wanting to achieve is to write the numbers 1, 2, 3 ... 8, 9, 10 to the console window in random order. So all the numbers will need to be written to console window, but the order of them must be random.
Part 2: In my actual project I plan to write all of the elements in an array, to the console window in random order. I am assuming that if I can get the answer to part 1, I should easily be able to implement this with an array.
/// <summary>
/// Returns all numbers, between min and max inclusive, once in a random sequence.
/// </summary>
IEnumerable<int> UniqueRandom(int minInclusive, int maxInclusive)
{
List<int> candidates = new List<int>();
for (int i = minInclusive; i <= maxInclusive; i++)
{
candidates.Add(i);
}
Random rnd = new Random();
while (candidates.Count > 0)
{
int index = rnd.Next(candidates.Count);
yield return candidates[index];
candidates.RemoveAt(index);
}
}
In your program
Console.WriteLine("All numbers between 0 and 10 in random order:");
foreach (int i in UniqueRandom(0, 10)) {
Console.WriteLine(i);
}
Enumerable.Range(1, 10).OrderBy(i => Guid.NewGuid()) works nicely.
using System;
using System.Collections;
namespace ConsoleApplication
{
class Numbers
{
public ArrayList RandomNumbers(int max)
{
// Create an ArrayList object that will hold the numbers
ArrayList lstNumbers = new ArrayList();
// The Random class will be used to generate numbers
Random rndNumber = new Random();
// Generate a random number between 1 and the Max
int number = rndNumber.Next(1, max + 1);
// Add this first random number to the list
lstNumbers.Add(number);
// Set a count of numbers to 0 to start
int count = 0;
do // Repeatedly...
{
// ... generate a random number between 1 and the Max
number = rndNumber.Next(1, max + 1);
// If the newly generated number in not yet in the list...
if (!lstNumbers.Contains(number))
{
// ... add it
lstNumbers.Add(number);
}
// Increase the count
count++;
} while (count <= 10 * max); // Do that again
// Once the list is built, return it
return lstNumbers;
}
}
Main
class Program
{
static int Main()
{
Numbers nbs = new Numbers();
const int Total = 10;
ArrayList lstNumbers = nbs.RandomNumbers(Total);
for (int i = 0; i < lstNumbers.Count; i++)
Console.WriteLine("{0}", lstNumbers[i].ToString());
return 0;
}
}
}
int[] ints = new int[11];
Random rand = new Random();
Random is a class built into .NET, and allows us to create random integers really, really easily. Basically all we have to do is call a method inside our rand object to get that random number, which is nice. So, inside our loop, we just set each element to the results of that method:
for (int i = 0; i < ints.Length; i++)
{
ints[i] = rand.Next(11);
}
We are essentially filling our entire array with random numbers here, all between 0 and 10. At this point all we have to do is display the contents for the user, which can be done with a foreach loop:
foreach (int i in ints)
{
Console.WriteLine(i.ToString());
}

Randomly pick 4 elements from an array using c#

I am trying to use random function in C# to randomly pick four from an array addetailsID which has over six elements.
I am placing these randomly picked into an another array strAdDetailsID:
string[] strAdDetailsID = new string[4];
for (int i = 0; i < 4; i++)
{
Random random = new Random();
int index = random.Next(0, addetailsID.Length);
value = addetailsID[index].ToString();
strAdDetailsID[i] = value;
}
Sometimes, I get two of the same values from the six elements. How can I get all four unique values to be picked?
You might be better off shuffling the array, and then choosing the first 4 elements.
You could do it with LINQ with this method.
List<string> list = new List<string>() { "There", "Are", "Many", "Elements", "To", "Arrays" };
foreach (var item in list.OrderBy(f => Guid.NewGuid()).Distinct().Take(4))
{
Console.WriteLine(item);
}
You have an issue with your placement of Random random ... but I believe you're attacking this the wrong way.
This could be solved by randomly ordering the source and taking the first 4 items.
var result = addetails.OrderBy(x => Guid.NewGuid()).Take(4).ToArray();
Assuming the contents of addetails are unique (like you imply), you will always get 4 unique values here. Using random correctly, it's still possible to get repeats (because it's random).
You need to generate 4 unique indices first, then pull the random values from the source array:
string[] addetailsID = new string[20]; // this is the array I want to index into
// generate the 4 unique indices into addetailsID
Random random = new Random();
List<int> indices = new List<int>();
while (indices.Count < 4)
{
int index = random.Next(0, addetailsID.Length);
if (indices.Count == 0 || !indices.Contains(index))
{
indices.Add(index);
}
}
// now get the 4 random values of interest
string[] strAdDetailsID = new string[4];
for (int i = 0; i < indices.Count; i++)
{
int randomIndex = indices[i];
strAdDetailsID[i] = addetailsID[randomIndex];
}
Put them in a list and remove the selected element from the list once it has been chosen.
The following algorithm works pretty well, and doesn't require extra storage or pre-shuffling. It does change the order of the source array, so if that's not feasible, then the pre-shuffling approach is best.
In pseudo-code:
result = []
For i = 0 to numItemsRequired:
randomIndex = random number between i and source.length - 1
result.add(source[randomIndex])
swap(source[randomIndex], source[i])
In C#:
string[] strAdDetailsID = new string[4];
Random rand = new Random();
for (int i = 0; i < 4; i++)
{
int randIndex = rand.Next(i, adDetailsID.Length);
strAddDetails[i] = adDetailsID[randIndex];
string temp = adDetailsID[randIndex];
adDetailsID[randIndex] = adDetailsID[i];
adDetails[i] = temp;
}
Use a list instead and drop every item that is already used:
List<string> addetailsID = new List<string>{"1","2","3","4","5","6"};
string[] strAdDetailsID = new string[4];
Random random = new Random();
for (int i = 0; i < 4; i++)
{
int index = random.Next(0, addetailsID.Count);
string value = addetailsID[index].ToString();
addetailsID.RemoveAt(index);
strAdDetailsID[i] = value;
}
strAdDetailsID.Dump();
Well, you should select random items one by one, not considering the already-picked items when selecting the next one. This must be faster than shuffling.
If the source list is small, you can just make a copy and remove the chosen items from it. Otherwise, you go like this:
(let n be the number of items in your array)
let S be the set of chosen indices; S = empty at the beginning
choose a random index i from 0 to n-1-size(S)
for each index from S that is smaller than i (starting from the smallest index!), add one to i
now i is a chosen index, add it to S.
return to step 2 until your set contains 4 elements.

Categories