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.
Related
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
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;
}
}
}
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 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();
I'm trying to create a binary search tree with unique random numbers. I'm using SortedSet to represent my tree and then I make it into an array and then I use Contains to see if a certain number is in the tree. My problem is that I can't figure out how to get all the random numbers different in a simple way. I used the methods Unik and Nålen_Unik but in this code it only generates 1 number to the array
Random random = new Random();
Program Tal = new Program();
string nål = Tal.Nålen_Unik();
string TalIArray = Tal.Unik();
bool found = false;
SortedSet<string> Tree = new SortedSet<string>();
for (int x = 0; x < 50000; x++)
{
Tree.Add(TalIArray);
}
int y = 0;
string[] TreeArray = Tree.ToArray<string>();
while (y < TreeArray.Length)
{
Console.WriteLine(TreeArray[y]);
y = y + 1;
}
private string Unik()
{
int maxSize = 4;
char[] chars = new char[10000];
string a;
a = "0123456789";
chars = a.ToCharArray();
int size = maxSize;
byte[] data = new byte[1];
RNGCryptoServiceProvider crypto = new RNGCryptoServiceProvider();
crypto.GetNonZeroBytes(data);
size = maxSize;
data = new byte[size];
crypto.GetNonZeroBytes(data);
StringBuilder result = new StringBuilder(size);
foreach (byte b in data)
{
result.Append(chars[b % (chars.Length - 1)]);
}
return result.ToString();
}
private string Nålen_Unik()
{
int maxSize = 1;
char[] chars = new char[62];
string a;
a = "0123456789";
chars = a.ToCharArray();
int size = maxSize;
byte[] data = new byte[1];
RNGCryptoServiceProvider crypto = new RNGCryptoServiceProvider();
crypto.GetNonZeroBytes(data);
size = maxSize;
data = new byte[size];
crypto.GetNonZeroBytes(data);
StringBuilder result = new StringBuilder(size);
foreach (byte b in data)
{
result.Append(chars[b % (chars.Length - 1)]);
}
return result.ToString();
There are mainly three approaches that are used to get random numbers without collisions:
Keep all numbers that you have picked, so that you can check a new number against all previous.
Create a range of unique numbers, shuffle them, and pick one at a time from the result.
Create such a huge random number that the risk of collisions is so small that it's negligible.
The second approach is the same principle as shuffling a deck of cards. The third approach is used when creating a GUID, which is basically a random 128 bit value.
You could use the Random class and a HashSet which will guarantee no duplicate items.
The HashSet class provides high-performance set operations. A set is a collection that contains no duplicate elements, and whose elements are in no particular order.
E.g:
HashSet<int> t = new HashSet<int>();
Random r = new Random();
while(t.Count < 50)//or the desired length of 't'
{
t.Add(r.Next(0,1000));//adjust min/max as needed
}
foreach (int i in t)
{
Console.WriteLine(i);
}
Console.Read();
Will give you a collection of 50 guaranteed unique random integers.
Since the number of elements in the set is not a requirement for this question it seems irrelevant to even mention, though if this is a requirement you can simply modify the line t.Count < ? to get a set of a desired length.
You could use Guid.NewGuid() or new Random().Next()
Assuming that you want unique numbers in a limited range, one (simple but possibly inefficient) way to do it is to create a list of all possible values (say, 0-99). Then you use System.Random to pick a random between 0 and (number of elements in list - 1). Get that index from the list, output it and remove the element. If you repeat the process, that element can no longer be generated and the numbers will be unique until you've used all possible values.
Create one instance of Random class. Make sure it is one!
then use this code
private Random random = new Random();
random.Next();