How to use Random class to shuffle array in C# [duplicate] - c#

This question already has answers here:
Best way to randomize an array with .NET
(19 answers)
Closed 1 year ago.
everyone. So I was trying to practice C# today, but I was stuck in figuring out how I can use the Random class to simply shuffle an array
like this for example:
using System;
public class Program
{
public static void Main()
{
int[] arr = {1,2,3,4,5};
Random rand = new Random();
for(int i =0; i < arr.Length; i++){
int shuffle = rand.Next(arr[i]);
Console.WriteLine(arr[shuffle]);
}
}
}
As you can see I tried to use this int shuffle = rand.Next(arr[i]); as a shuffler, but
I guess it just duplicates some elements in the array.I'm still noob at this, thanks in advance for the response.

You can try implementing Fisher-Yates shuffling algorithm: https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle
Random random = new Random();
...
for (int i = 0; i < array.Length - 1; ++i)
{
int r = random.Next(i, array.Length);
(array[r], array[i]) = (array[i], array[r]);
}
I suggest extracting a method for this:
// Easiest, but not thread safe
private static Random random = new Random();
private static void Shuffle<T>(T[] array)
{
if (array is null)
throw new ArgumentNullException(nameof(array));
for (int i = 0; i < array.Length - 1; ++i)
{
int r = random.Next(i, array.Length);
(array[r], array[i]) = (array[i], array[r]);
}
}
And you can call it from Main:
Shuffle(array);
You can fiddle with the algorithm.

There are a few solutions out there, but the one I had used it to create a random array and sort based on that
static class Program
{
static void Main(string[] args)
{
var array = new[] { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
Shuffle(ref array);
foreach (var item in array)
{
Console.WriteLine(item);
}
// Fri
// Wed
// Sat
// Thu
// Mon
// Sun
// Tue
}
static readonly Random rng = new Random();
public static void Shuffle<T>(ref T[] array)
{
double[] key = new double[array.Length];
for (int i = 0; i < key.Length; i++)
{
key[i] = rng.NextDouble();
}
Array.Sort(key, array);
}
}
An alternative is to use the following 1 liner LINQ statement
static void Main(string[] args)
{
var array = new[] { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
var result = array.OrderBy((item) => rng.NextDouble()).ToArray();
}

This type of shuffling is going to require seeding the Randomn class to the size of the array. And with each pass in the for loop, it's going to swap the current number with a random other number in the array.
Here is a sample of what the shuffle can look like:
int[] arr = {1,2,3,4,5};
Random rand = new Random();
for(int i = 0; i < arr.Length; i++){
int shuffle = rand.Next(arr.Length);
int n = arr[i];
arr.SetValue(arr[shuffle], i);
arr.SetValue(n, shuffle);
}
Console.Write('[' + arr[0].ToString());
for(int i = 1; i < arr.Length; i++){
Console.Write("," + arr[i]);
}
Console.Write("]");

Related

Creating an array of 10 elements and assigning them by counting randomly

Creating an array of 10 elements and assigning them by counting randomly, assigning a new number if the same numbers are repeated
I tried to use the contains method but it didn't appear in the list after the array, I used the exists method but it didn't work either, what kind of way should I follow? thanks
static void Main(string[] args)
{
Random Rnd = new Random();
int[] Numbers = new int[10];
for (int i = 0; i < Numbers.Length; i++)
{
int rast = Rnd.Next(10);
bool b = Array.Exists(Numbers, element => element == rast);
if (!b)
{
i--;
}
else { Numbers[i] = rast; }
}
foreach (int item in Numbers)
{
Console.WriteLine(item);
}
}
It appears that you want the numbers from 0 to 9 in an array in random order. If that is so:
var rng = new Random();
var numbers = Enumerable.Range(0, 10).OrderBy(n => rng.NextDouble()).ToArray();
You're close, but there are two issues in your algorithm:
if (!b) should be if (b)
Rnd.Next(1,10) gets numbers between 1 and 9 so you will never get a 10 and the algorithm will never finish.
After fixing these two your program will work.
Anyway, here's a version that uses .Contains
Random Rnd = new Random();
int[] Numbers = new int[10];
for (int i = 0; i < Numbers.Length; i++)
{
// + 1 because the range of return values includes minValue but not maxValue.
int r = Rnd.Next(minValue: 1, maxValue: Numbers.Length + 1);
while(Numbers.Contains(r))
{
r = Rnd.Next(minValue: 1, maxValue: Numbers.Length + 1);
}
Numbers[i] = r;
}
Console.WriteLine(string.Join(",", Numbers));
Example output:
9,8,7,1,4,6,3,10,5,2
Here's an example. I hope this is the output you want.
public static void Main()
{
Random Rnd = new Random();
int[] Numbers = new int[10];
for (int i = 0; i < Numbers.Length; i++)
{
int rast = Rnd.Next(10);
bool b = Array.Exists(Numbers, element => element == rast);
if (!b)
{
Numbers[i] = rast;
Console.WriteLine(rast);
}
else {
i--;
}
}
}
As a result, I have found the solution, thanks to everyone who answered and showed me the way
int[] Numbers = new int[10];
int x, y;
Random ran = new Random();
for (x = 0; x < 10; x++)
{
Numbers[x] = ran.Next(1, 10);
for (y = x; y >= 0; y--)
{
if (x == y)
{
continue;
}
if (Numbers[x] == Numbers[y])
{
Numbers[x] = ran.Next(1, 10);
y = x;
}
}
Console.WriteLine(Numbers[x]);
}
when i created new project as Console .net in visual studio 2019 ,
it doesnt bring this libraries automatically ,
Because the following libraries are not attached, the codings I used before did not work, I developed another simple solution, and in this way, I realized that I had a problem due to these libraries not being attached.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
int[] Numbers= new int[10];
Random rnd = new Random();
for (int i = 0; i < Numbers.Length; i++)
{
int Num= rnd.Next(10);
if (Numbers.Contains(Num))
{
i--;
}
else
{
Console.WriteLine(Numbers[i] = Num);
}
}

Generate and store 7 random numbers in a array

I made a program to generate 7 random numbers for a lottery using a array. I have generated a random number between 1, 50 but every number shows in order and not on the same line. I would also like to store the auto generated numbers in a array to use. I am not sure how to fix this any help would be appreciated
static void AutoGenrateNumbers()
{
int temp;
int number = 0;
int[] lotto = new int[7];
Random rand = new Random();
for (int i = 0; i <= 50; i++)
{
number = 0;
temp = rand.Next(1, 50);
while (number <= i)
{
if (temp == number)
{
number = 0;
temp = rand.Next(1, 50);
}
else
{
number++;
}
}
temp = number;
Console.WriteLine($"the new lotto winning numbers are:{number}Bonus:{number}");
}
}
Is this what you need?
static void AutoGenrateNumbers()
{
int temp;
int[] lotto = new int[7];
Random rand = new Random();
for (int i = 0; i < 7; i++)
{
temp = rand.Next(1, 50);
lotto[i]= temp;
}
Console.Write($"the new lotto winning numbers are: ");
for (int i = 0; i < 6; i++)
{
Console.Write(lotto[i]+" ");
}
Console.Write($"Bonus:{lotto[6]}");
}
edit: if you want the numbers to be unique:
static void AutoGenrateNumbers()
{
int temp;
int[] lotto = new int[7];
Random rand = new Random();
for (int i = 0; i < 7; i++)
{
do
{
temp = rand.Next(1, 50);
}
while (lotto.Contains(temp));
lotto[i]= temp;
}
Console.Write($"the new lotto winning numbers are: ");
for (int i = 0; i < 6; i++)
{
Console.Write(lotto[i]+" ");
}
Console.Write($"Bonus:{lotto[6]}");
}
A better way to do this is just to generate all the numbers 1-50, shuffle them and then just take 7. Using Jon Skeet's Shuffle extension method found here:
public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> source, Random rng)
{
T[] elements = source.ToArray();
for (int i = elements.Length - 1; i >= 0; i--)
{
int swapIndex = rng.Next(i + 1);
yield return elements[swapIndex];
elements[swapIndex] = elements[i];
}
}
Now your code is very simple:
static void AutoGenrateNumbers()
{
var lotto = Enumerable.Range(0, 50).Shuffle(new Random()).Take(7);
Console.WriteLine("the new lotto winning numbers are: {0}", string.Join(",", lotto));
}
Fiddle here
Just to add to the existing answers tried to do that in one LINQ statement:
static void Main(string[] args)
{
var rand = new Random();
Enumerable
.Range(1, 7)
.Aggregate(new List<int>(), (x, y) =>
{
var num = rand.Next(1, 51);
while (x.Contains(num))
{
num = rand.Next(1, 51);
}
x.Add(num);
return x;
})
.ForEach(x => Console.Write($"{x} "));
}
The result is something like:
34 24 46 27 11 17 2

How can I fill array with unique random numbers with for-loop&if-statement?

I'm trying to fill one dimensional array with random BUT unique numbers (No single number should be same). As I guess I have a logical error in second for loop, but can't get it right.
P.S I'm not looking for a more "complex" solution - all I know at is this time is while,for,if.
P.P.S I know that it's a really beginner's problem and feel sorry for this kind of question.
int[] x = new int[10];
for (int i = 0; i < x.Length; i++)
{
x[i] = r.Next(9);
for (int j = 0; j <i; j++)
{
if (x[i] == x[j]) break;
}
}
for (int i = 0; i < x.Length; i++)
{
Console.WriteLine(x[i);
}
Here is a solution with your code.
int[] x = new int[10];
for (int i = 0; i < x.Length;)
{
bool stop = false;
x[i] = r.Next(9);
for (int j = 0; j <i; j++)
{
if (x[i] == x[j]) {
stop = true;
break;
}
}
if (!stop)
i++;
}
for (int i = 0; i < x.Length; i++)
{
Console.WriteLine(x[i]);
}
A simple trace of the posted code reveals some of the issues. To be specific, on the line…
if (x[i] == x[j]) break;
if the random number is “already” in the array, then simply breaking out of the j loop is going to SKIP the current i value into the x array. This means that whenever a duplicate is found, x[i] is going to be 0 (zero) the default value, then skipped.
The outer i loop is obviously looping through the x int array, this is pretty clear and looks ok. However, the second inner loop can’t really be a for loop… and here’s why… basically you need to find a random int, then loop through the existing ints to see if it already exists. Given this, in theory you could grab the same random number “many” times over before getting a unique one. Therefore, in this scenario… you really have NO idea how many times you will loop around before you find this unique number.
With that said, it may help to “break” your problem down. I am guessing a “method” that returns a “unique” int compared to the existing ints in the x array, may come in handy. Create an endless while loop, inside this loop, we would grab a random number, then loop through the “existing” ints. If the random number is not a duplicate, then we can simply return this value. This is all this method does and it may look something like below.
private static int GetNextInt(Random r, int[] x, int numberOfRandsFound) {
int currentRand;
bool itemAlreadyExist = false;
while (true) {
currentRand = r.Next(RandomNumberSize);
itemAlreadyExist = false;
for (int i = 0; i < numberOfRandsFound; i++) {
if (x[i] == currentRand) {
itemAlreadyExist = true;
break;
}
}
if (!itemAlreadyExist) {
return currentRand;
}
}
}
NOTE: Here would be a good time to describe a possible endless loop in this code…
Currently, the random numbers and the size of the array are the same, however, if the array size is “larger” than the random number spread, then the code above will NEVER exit. Example, if the current x array is set to size 11 and the random numbers is left at 10, then you will never be able to set the x[10] item since ALL possible random numbers are already used. I hope that makes sense.
Once we have the method above… the rest should be fairly straight forward.
static int DataSize;
static int RandomNumberSize;
static void Main(string[] args) {
Random random = new Random();
DataSize = 10;
RandomNumberSize = 10;
int numberOfRandsFound = 0;
int[] ArrayOfInts = new int[DataSize];
int currentRand;
for (int i = 0; i < ArrayOfInts.Length; i++) {
currentRand = GetNextInt(random, ArrayOfInts, numberOfRandsFound);
ArrayOfInts[i] = currentRand;
numberOfRandsFound++;
}
for (int i = 0; i < ArrayOfInts.Length; i++) {
Console.WriteLine(ArrayOfInts[i]);
}
Console.ReadKey();
}
Lastly as other have mentioned, this is much easier with a List<int>…
static int DataSize;
static int RandomNumberSize;
static void Main(string[] args) {
Random random = new Random();
DataSize = 10;
RandomNumberSize = 10;
List<int> listOfInts = new List<int>();
bool stillWorking = true;
int currentRand;
while (stillWorking) {
currentRand = random.Next(RandomNumberSize);
if (!listOfInts.Contains(currentRand)) {
listOfInts.Add(currentRand);
if (listOfInts.Count == DataSize)
stillWorking = false;
}
}
for (int i = 0; i < listOfInts.Count; i++) {
Console.WriteLine(i + " - " + listOfInts[i]);
}
Console.ReadKey();
}
Hope this helps ;-)
The typical solution is to generate the entire potential set in sequence (in this case an array with values from 0 to 9). Then shuffle the sequence.
private static Random rng = new Random();
public static void Shuffle(int[] items)
{
int n = list.Length;
while (n > 1) {
n--;
int k = rng.Next(n + 1);
int temp = items[k];
items[k] = items[n];
items[n] = temp;
}
}
static void Main(string[] args)
{
int[] x = new int[10];
for(int i = 0; i<x.Length; i++)
{
x[i] = i;
}
Shuffle(x);
for(int i = 0; i < x.Length; i++)
{
Console.WritLine(x[i]);
}
}
//alternate version of Main()
static void Main(string[] args)
{
var x = Enumerable.Range(0,10).ToArray();
Shuffle(x);
Console.WriteLine(String.Join("\n", x));
}
You can simply do this:
private void AddUniqueNumber()
{
Random r = new Random();
List<int> uniqueList = new List<int>();
int num = 0, count = 10;
for (int i = 0; i < count; i++)
{
num = r.Next(count);
if (!uniqueList.Contains(num))
uniqueList.Add(num);
}
}
Or:
int[] x = new int[10];
Random r1 = new Random();
int num = 0;
for (int i = 0; i < x.Length; i++)
{
num = r1.Next(10);
x[num] = num;
}

returning random int from method to array

In my code i have static int method that should return an array of random integers. The problem is when i print an array, only the last number is random int, and other ints are all zeros.
static void Main(string[] args)
{
int a = int.Parse(Console.ReadLine());
int[] array = mtd(a);
for (int i = 0; i < array.Length; i++)
{
Console.WriteLine(array[i]);
}
}
public static int[] mtd(int b)
{
int[] arr = new int[b];
Array.Resize<int>(ref arr, b);
Random rand = new Random();
for (int i = 0; i < arr.Length; i++)
{
arr.SetValue(rand.Next(1, 5), arr.Length - 1);
}
return arr;
}
In the for loop in your method mtd you are always setting the last value of your array arr by using arr.Length - 1. Use i instead:
for (int i = 0; i < arr.Length; i++)
{
arr[i] = rand.Next(1, 5);
}
Or with arr.SetValue:
for (int i = 0; i < arr.Length; i++)
{
arr.SetValue(rand.Next(1, 5), i);
}
Working one :
public static int[] mtd(int b)
{
int[] arr = new int[b];
Random rand = new Random();
for (int i = 0; i < arr.Length; i++)
{
arr.SetValue(rand.Next(1, 5), i);
}
return arr;
}
EDIT : Btw the Array.resize is useless here, you already define the length of your array. ( new int[b] set the length of the array to b )
Your problem was that you never used i, so you just set the value of the last value of your array.
I modified and simplified your code:
public static int[] mtd(int b)
{
int[] arr = new int[b];
Random rand = new Random();
for (int i = 0; i < arr.Length; i++)
arr[i] = rand.Next(1, 5);
return arr;
}

Select a number randomly from 1 to 99

I want to select a random number from 1 to 99. And then select the number again but this time discard the previous number. Can someone help me.
private List<int> numbers = Enumerable.Range(0, 100).ToList();
private Random rnd = new Random();
public int GetRandomInt()
{
var index = rnd.Next(0, numbers.Length);
var number = numbers[index];
numbers.RemoveAt(index);
return number;
}
Here's what I'd do:
var rnd = new Random();
var numbers = new Stack<int>(Enumerable.Range(1, 99).OrderBy(x => rnd.Next()));
You effectively are randomizing the list of numbers and then adding them to a stack. Now you just have to do this to get each number:
var next = numbers.Pop()
You stop when numbers.Count == 0. Simple.
Here is the revised version of Khanh TO, because it is not correct:
List<int> usedNumbers = new List<int>();
Random rand = new Random(new object().GetHashCode());
int number = 0;
for (int i = 0; i < 99; i++)
{
do
{
number = 1 + rand.Next(0, 99);
} while (usedNumbers.Contains(number));
usedNumbers.Add(number);
}
I usually do it with arrays.
Whenever you create a random number just put on the array. so next time check if the number is already generated by checking in the array.
Try this
IList<int> arr = Enumerable.Range(1, 99).ToList();
int randNum;
Random rnd = new Random();
randNum = rnd.Next(1, arr.Count());
MessageBox.Show(randNum.ToString());
arr = arr.Where(x => x != randNum).ToList();
Can I go for the shortest code, without a nested loop, or removing list elements.
Code 1
class Program
{
static Random rnd=new Random();
static void Main(string[] args)
{
var list=new SortedDictionary<double, int>();
// Fill list
for (int i=1; i<=99; i++)
{
list.Add(rnd.NextDouble(), i);
}
// List Automatically random
var random_int=list.Values.ToArray();
// random_int = {45, 7, 72, .. }
}
}
Code 2
class Program
{
static Random rnd=new Random();
static void Main(string[] args)
{
var list=new int[99];
// Fill list
for (int i=1; i<=99; i++)
{
list[i-1]=i;
}
Comparison<int> any=(x, y) =>
{
var z=2*rnd.NextDouble()-1;
return z.CompareTo(0);
};
// Randomize List
Array.Sort(list, any);
// list = { 49, 59, 21, 7, 18 ...}
}
}

Categories