Foreach list search without repetition [duplicate] - c#

This question already has answers here:
C# creating a list of random unique integers
(6 answers)
Closed 4 years ago.
How I can put randomize numbers to list without repetition?
Here's my code, sometimes the numbers are repeated but I do not know why
Random losowa = new Random();
List<int> pula = new List<int>();
private void LosujPytania()
{
int a = losowa.Next(1,20);
while (pula.Count < 10)
{
foreach (int i in pula)
{
if (a == i)
{
a = losowa.Next(1, 20);
break;
}
}
pula.Add(a);
}
}

Code below create list of numbers without repetition. Key to resolve problem is use list.Contains().
using System;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
var list = new List<int>();
var rand = new Random();
while(list.Count <10)
{
var number = rand.Next(1,20);
if(! list.Contains(number))
list.Add(number);
}
foreach(var item in list)
Console.WriteLine(item);
}
}

You should check if this number was previously generated and generate another number if it is repeated.
Change this:
private void LosujPytania()
{
int a = losowa.Next(1,20);
while (pula.Count < 10)
{
foreach (int i in pula)
{
if (a == i)
{
a = losowa.Next(1, 20);
break;
}
}
pula.Add(a);
}
}
by this:
private void LosujPytania()
{
int a = losowa.Next(1,20);
pula.Add(a);
while (pula.Count < 10)
{
do
{
a = losowa.Next(1, 20);
} while(pula.Contains(a));
pula.Add(a);
}
}

You can do this, you can check my comments additional details:
private static void LosujPytania()
{
Random losowa = new Random();
List<int> pula = new List<int>();
int a = losowa.Next(1,20);
while (pula.Count < 10)
{
//Your code is not really checking for duplicates so I replace it with boolean condition below
//foreach (int i in pula)
//{
// if (a == i)
// {
// a = losowa.Next(1, 20);
// break;
// }
//}
a = losowa.Next(1, 20);
//This will check if your list doesn't contain your numbers yet before adding to make sure everything is unique
if (!pula.Contains(a))
pula.Add(a);
}
}

if you want numbers without replications,
I think it will be better to use HashSet.
Random losowa = new Random();
HashSet<int> pula = new HashSet<int>();
while (pula.Count < 10)
{
pula.Add(r.Next(20));
}
or if you really need the List, you can use a helper method
something like:
private void LosujPytania()
{
Random losowa = new Random();
List<int> pula = new List<int>();
int a = losowa.Next(1, 20);
pula.AddRange(Get10RandomNumbers(losowa));
}
private IEnumerable<int> Get10RandomNumbers(Random losowa)
{
HashSet<int> ints = new HashSet<int>();
while (ints.Count < 10)
{
ints.Add(losowa.Next(20));
}
return ints;
}

A simple 2 lines solution:
var rnd = new Random();
var list = Enumerable.Range(0, 20).OrderBy(x => rnd.Next()).Take(10).ToList();
Explanation:
Enumerable.Range(0, 20) will return an IEnumerable<int> with the numbers 0 to 19.
OrderBy(x => rnd.Next()) will sort the values to a random order.
Take(10) will return the first 10 numbers from the IEnumerable<int>,
and finally, ToList() will return a list of these int values.

Related

Shuffle Array and make sure elements are not repeating [duplicate]

What is the best way to randomize the order of a generic list in C#? I've got a finite set of 75 numbers in a list I would like to assign a random order to, in order to draw them for a lottery type application.
Shuffle any (I)List with an extension method based on the Fisher-Yates shuffle:
private static Random rng = new Random();
public static void Shuffle<T>(this IList<T> list)
{
int n = list.Count;
while (n > 1) {
n--;
int k = rng.Next(n + 1);
T value = list[k];
list[k] = list[n];
list[n] = value;
}
}
Usage:
List<Product> products = GetProducts();
products.Shuffle();
The code above uses the much criticised System.Random method to select swap candidates. It's fast but not as random as it should be. If you need a better quality of randomness in your shuffles use the random number generator in System.Security.Cryptography like so:
using System.Security.Cryptography;
...
public static void Shuffle<T>(this IList<T> list)
{
RNGCryptoServiceProvider provider = new RNGCryptoServiceProvider();
int n = list.Count;
while (n > 1)
{
byte[] box = new byte[1];
do provider.GetBytes(box);
while (!(box[0] < n * (Byte.MaxValue / n)));
int k = (box[0] % n);
n--;
T value = list[k];
list[k] = list[n];
list[n] = value;
}
}
A simple comparison is available at this blog (WayBack Machine).
Edit: Since writing this answer a couple years back, many people have commented or written to me, to point out the big silly flaw in my comparison. They are of course right. There's nothing wrong with System.Random if it's used in the way it was intended. In my first example above, I instantiate the rng variable inside of the Shuffle method, which is asking for trouble if the method is going to be called repeatedly. Below is a fixed, full example based on a really useful comment received today from #weston here on SO.
Program.cs:
using System;
using System.Collections.Generic;
using System.Threading;
namespace SimpleLottery
{
class Program
{
private static void Main(string[] args)
{
var numbers = new List<int>(Enumerable.Range(1, 75));
numbers.Shuffle();
Console.WriteLine("The winning numbers are: {0}", string.Join(", ", numbers.GetRange(0, 5)));
}
}
public static class ThreadSafeRandom
{
[ThreadStatic] private static Random Local;
public static Random ThisThreadsRandom
{
get { return Local ?? (Local = new Random(unchecked(Environment.TickCount * 31 + Thread.CurrentThread.ManagedThreadId))); }
}
}
static class MyExtensions
{
public static void Shuffle<T>(this IList<T> list)
{
int n = list.Count;
while (n > 1)
{
n--;
int k = ThreadSafeRandom.ThisThreadsRandom.Next(n + 1);
T value = list[k];
list[k] = list[n];
list[n] = value;
}
}
}
}
If we only need to shuffle items in a completely random order (just to mix the items in a list), I prefer this simple yet effective code that orders items by guid...
var shuffledcards = cards.OrderBy(a => Guid.NewGuid()).ToList();
As people have pointed out in the comments, GUIDs are not guaranteed to be random, so we should be using a real random number generator instead:
private static Random rng = new Random();
...
var shuffledcards = cards.OrderBy(a => rng.Next()).ToList();
I'm bit surprised by all the clunky versions of this simple algorithm here. Fisher-Yates (or Knuth shuffle) is bit tricky but very compact. Why is it tricky? Because your need to pay attention to whether your random number generator r(a,b) returns value where b is inclusive or exclusive. I've also edited Wikipedia description so people don't blindly follow pseudocode there and create hard to detect bugs. For .Net, Random.Next(a,b) returns number exclusive of b so without further ado, here's how it can be implemented in C#/.Net:
public static void Shuffle<T>(this IList<T> list, Random rnd)
{
for(var i=list.Count; i > 0; i--)
list.Swap(0, rnd.Next(0, i));
}
public static void Swap<T>(this IList<T> list, int i, int j)
{
var temp = list[i];
list[i] = list[j];
list[j] = temp;
}
Try this code.
Extension method for IEnumerable:
public static IEnumerable<T> Randomize<T>(this IEnumerable<T> source)
{
Random rnd = new Random();
return source.OrderBy<T, int>((item) => rnd.Next());
}
Idea is get anonymous object with item and random order and then reorder items by this order and return value:
var result = items.Select(x => new { value = x, order = rnd.Next() })
.OrderBy(x => x.order).Select(x => x.value).ToList()
public static List<T> Randomize<T>(List<T> list)
{
List<T> randomizedList = new List<T>();
Random rnd = new Random();
while (list.Count > 0)
{
int index = rnd.Next(0, list.Count); //pick a random item from the master list
randomizedList.Add(list[index]); //place it at the end of the randomized list
list.RemoveAt(index);
}
return randomizedList;
}
EDIT
The RemoveAt is a weakness in my previous version. This solution overcomes that.
public static IEnumerable<T> Shuffle<T>(
this IEnumerable<T> source,
Random generator = null)
{
if (generator == null)
{
generator = new Random();
}
var elements = source.ToArray();
for (var i = elements.Length - 1; i >= 0; i--)
{
var swapIndex = generator.Next(i + 1);
yield return elements[swapIndex];
elements[swapIndex] = elements[i];
}
}
Note the optional Random generator, if the base framework implementation of Random is not thread-safe or cryptographically strong enough for your needs, you can inject your implementation into the operation.
A suitable implementation for a thread-safe cryptographically strong Random implementation can be found in this answer.
Here's an idea, extend IList in a (hopefully) efficient way.
public static IEnumerable<T> Shuffle<T>(this IList<T> list)
{
var choices = Enumerable.Range(0, list.Count).ToList();
var rng = new Random();
for(int n = choices.Count; n > 1; n--)
{
int k = rng.Next(n);
yield return list[choices[k]];
choices.RemoveAt(k);
}
yield return list[choices[0]];
}
This is my preferred method of a shuffle when it's desirable to not modify the original. It's a variant of the Fisher–Yates "inside-out" algorithm that works on any enumerable sequence (the length of source does not need to be known from start).
public static IList<T> NextList<T>(this Random r, IEnumerable<T> source)
{
var list = new List<T>();
foreach (var item in source)
{
var i = r.Next(list.Count + 1);
if (i == list.Count)
{
list.Add(item);
}
else
{
var temp = list[i];
list[i] = item;
list.Add(temp);
}
}
return list;
}
This algorithm can also be implemented by allocating a range from 0 to length - 1 and randomly exhausting the indices by swapping the randomly chosen index with the last index until all indices have been chosen exactly once. This above code accomplishes the exact same thing but without the additional allocation. Which is pretty neat.
With regards to the Random class it's a general purpose number generator (and If I was running a lottery I'd consider using something different). It also relies on a time based seed value by default. A small alleviation of the problem is to seed the Random class with the RNGCryptoServiceProvider or you could use the RNGCryptoServiceProvider in a method similar to this (see below) to generate uniformly chosen random double floating point values but running a lottery pretty much requires understanding randomness and the nature of the randomness source.
var bytes = new byte[8];
_secureRng.GetBytes(bytes);
var v = BitConverter.ToUInt64(bytes, 0);
return (double)v / ((double)ulong.MaxValue + 1);
The point of generating a random double (between 0 and 1 exclusively) is to use to scale to an integer solution. If you need to pick something from a list based on a random double x that's always going to be 0 <= x && x < 1 is straight forward.
return list[(int)(x * list.Count)];
Enjoy!
If you don't mind using two Lists, then this is probably the easiest way to do it, but probably not the most efficient or unpredictable one:
List<int> xList = new List<int>() { 1, 2, 3, 4, 5 };
List<int> deck = new List<int>();
foreach (int xInt in xList)
deck.Insert(random.Next(0, deck.Count + 1), xInt);
I usually use:
var list = new List<T> ();
fillList (list);
var randomizedList = new List<T> ();
var rnd = new Random ();
while (list.Count != 0)
{
var index = rnd.Next (0, list.Count);
randomizedList.Add (list [index]);
list.RemoveAt (index);
}
You can achieve that be using this simple extension method
public static class IEnumerableExtensions
{
public static IEnumerable<t> Randomize<t>(this IEnumerable<t> target)
{
Random r = new Random();
return target.OrderBy(x=>(r.Next()));
}
}
and you can use it by doing the following
// use this on any collection that implements IEnumerable!
// List, Array, HashSet, Collection, etc
List<string> myList = new List<string> { "hello", "random", "world", "foo", "bar", "bat", "baz" };
foreach (string s in myList.Randomize())
{
Console.WriteLine(s);
}
Just wanted to suggest a variant using an IComparer<T> and List.Sort():
public class RandomIntComparer : IComparer<int>
{
private readonly Random _random = new Random();
public int Compare(int x, int y)
{
return _random.Next(-1, 2);
}
}
Usage:
list.Sort(new RandomIntComparer());
One can use the Shuffle extension methond from morelinq package, it works on IEnumerables
install-package morelinq
using MoreLinq;
...
var randomized = list.Shuffle();
If you have a fixed number (75), you could create an array with 75 elements, then enumerate your list, moving the elements to randomized positions in the array. You can generate the mapping of list number to array index using the Fisher-Yates shuffle.
You can make the Fisher-Yates shuffle more terse and expressive by using tuples for the swap.
private static readonly Random random = new Random();
public static void Shuffle<T>(this IList<T> list)
{
int n = list.Count;
while (n > 1)
{
n--;
int k = random.Next(n + 1);
(list[k], list[n]) = (list[n], list[k]);
}
}
I have found an interesting solution online.
Courtesy: https://improveandrepeat.com/2018/08/a-simple-way-to-shuffle-your-lists-in-c/
var shuffled = myList.OrderBy(x => Guid.NewGuid()).ToList();
We can use an extension method for List and use a thread-safe random generator combination. I've packaged an improved version of this on NuGet with the source code available on GitHub. The NuGet version contains optional cryptographically-strong random.
Pre-.NET 6.0 version:
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Shuffle<T>(this IList<T> list)
{
if (list == null) throw new ArgumentNullException(nameof(list));
int n = list.Count;
while (n > 1)
{
int k = ThreadSafeRandom.Instance.Next(n--);
(list[n], list[k]) = (list[k], list[n]);
}
}
internal class ThreadSafeRandom
{
public static Random Instance => _local.Value;
private static readonly Random _global = new Random();
private static readonly ThreadLocal<Random> _local = new ThreadLocal<Random>(() =>
{
int seed;
lock (_global)
{
seed = _global.Next();
}
return new Random(seed);
});
}
On .NET 6.0 or later:
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Shuffle<T>(this IList<T> list)
{
ArgumentNullException.ThrowIfNull(list);
int n = list.Count;
while (n > 1)
{
int k = Random.Shared.Next(n--);
(list[n], list[k]) = (list[k], list[n]);
}
}
Install the library via NuGet for more features.
A simple modification of the accepted answer that returns a new list instead of working in-place, and accepts the more general IEnumerable<T> as many other Linq methods do.
private static Random rng = new Random();
/// <summary>
/// Returns a new list where the elements are randomly shuffled.
/// Based on the Fisher-Yates shuffle, which has O(n) complexity.
/// </summary>
public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> list) {
var source = list.ToList();
int n = source.Count;
var shuffled = new List<T>(n);
shuffled.AddRange(source);
while (n > 1) {
n--;
int k = rng.Next(n + 1);
T value = shuffled[k];
shuffled[k] = shuffled[n];
shuffled[n] = value;
}
return shuffled;
}
List<T> OriginalList = new List<T>();
List<T> TempList = new List<T>();
Random random = new Random();
int length = OriginalList.Count;
int TempIndex = 0;
while (length > 0) {
TempIndex = random.Next(0, length); // get random value between 0 and original length
TempList.Add(OriginalList[TempIndex]); // add to temp list
OriginalList.RemoveAt(TempIndex); // remove from original list
length = OriginalList.Count; // get new list <T> length.
}
OriginalList = new List<T>();
OriginalList = TempList; // copy all items from temp list to original list.
Here is an implementation of the Fisher-Yates shuffle that allows specification of the number of elements to return; hence, it is not necessary to first sort the whole collection before taking your desired number of elements.
The sequence of swapping elements is reversed from default; and proceeds from the first element to the last element, so that retrieving a subset of the collection yields the same (partial) sequence as shuffling the whole collection:
collection.TakeRandom(5).SequenceEqual(collection.Shuffle().Take(5)); // true
This algorithm is based on Durstenfeld's (modern) version of the Fisher-Yates shuffle on Wikipedia.
public static IList<T> TakeRandom<T>(this IEnumerable<T> collection, int count, Random random) => shuffle(collection, count, random);
public static IList<T> Shuffle<T>(this IEnumerable<T> collection, Random random) => shuffle(collection, null, random);
private static IList<T> shuffle<T>(IEnumerable<T> collection, int? take, Random random)
{
var a = collection.ToArray();
var n = a.Length;
if (take <= 0 || take > n) throw new ArgumentException("Invalid number of elements to return.");
var end = take ?? n;
for (int i = 0; i < end; i++)
{
var j = random.Next(i, n);
(a[i], a[j]) = (a[j], a[i]);
}
if (take.HasValue) return new ArraySegment<T>(a, 0, take.Value);
return a;
}
Implementation:
public static class ListExtensions
{
public static void Shuffle<T>(this IList<T> list, Random random)
{
for (var i = list.Count - 1; i > 0; i--)
{
int indexToSwap = random.Next(i + 1);
(list[indexToSwap], list[i]) = (list[i], list[indexToSwap]);
}
}
}
Example:
var random = new Random();
var array = new [] { 1, 2, 3 };
array.Shuffle(random);
foreach (var item in array) {
Console.WriteLine(item);
}
Demonstration in .NET Fiddle
Here's an efficient Shuffler that returns a byte array of shuffled values. It never shuffles more than is needed. It can be restarted from where it previously left off. My actual implementation (not shown) is a MEF component that allows a user specified replacement shuffler.
public byte[] Shuffle(byte[] array, int start, int count)
{
int n = array.Length - start;
byte[] shuffled = new byte[count];
for(int i = 0; i < count; i++, start++)
{
int k = UniformRandomGenerator.Next(n--) + start;
shuffled[i] = array[k];
array[k] = array[start];
array[start] = shuffled[i];
}
return shuffled;
}
`
Your question is how to randomize a list. This means:
All unique combinations should be possible of happening
All unique combinations should occur with the same distribution (AKA being non-biased).
A large number of the answers posted for this question do NOT satisfy the two requirements above for being "random".
Here's a compact, non-biased pseudo-random function following the Fisher-Yates shuffle method.
public static void Shuffle<T>(this IList<T> list, Random rnd)
{
for (var i = list.Count-1; i > 0; i--)
{
var randomIndex = rnd.Next(i + 1); //maxValue (i + 1) is EXCLUSIVE
list.Swap(i, randomIndex);
}
}
public static void Swap<T>(this IList<T> list, int indexA, int indexB)
{
var temp = list[indexA];
list[indexA] = list[indexB];
list[indexB] = temp;
}
Here's a thread-safe way to do this:
public static class EnumerableExtension
{
private static Random globalRng = new Random();
[ThreadStatic]
private static Random _rng;
private static Random rng
{
get
{
if (_rng == null)
{
int seed;
lock (globalRng)
{
seed = globalRng.Next();
}
_rng = new Random(seed);
}
return _rng;
}
}
public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> items)
{
return items.OrderBy (i => rng.Next());
}
}
public Deck(IEnumerable<Card> initialCards)
{
cards = new List<Card>(initialCards);
public void Shuffle()
}
{
List<Card> NewCards = new List<Card>();
while (cards.Count > 0)
{
int CardToMove = random.Next(cards.Count);
NewCards.Add(cards[CardToMove]);
cards.RemoveAt(CardToMove);
}
cards = NewCards;
}
public IEnumerable<string> GetCardNames()
{
string[] CardNames = new string[cards.Count];
for (int i = 0; i < cards.Count; i++)
CardNames[i] = cards[i].Name;
return CardNames;
}
Deck deck1;
Deck deck2;
Random random = new Random();
public Form1()
{
InitializeComponent();
ResetDeck(1);
ResetDeck(2);
RedrawDeck(1);
RedrawDeck(2);
}
private void ResetDeck(int deckNumber)
{
if (deckNumber == 1)
{
int numberOfCards = random.Next(1, 11);
deck1 = new Deck(new Card[] { });
for (int i = 0; i < numberOfCards; i++)
deck1.Add(new Card((Suits)random.Next(4),(Values)random.Next(1, 14)));
deck1.Sort();
}
else
deck2 = new Deck();
}
private void reset1_Click(object sender, EventArgs e) {
ResetDeck(1);
RedrawDeck(1);
}
private void shuffle1_Click(object sender, EventArgs e)
{
deck1.Shuffle();
RedrawDeck(1);
}
private void moveToDeck1_Click(object sender, EventArgs e)
{
if (listBox2.SelectedIndex >= 0)
if (deck2.Count > 0) {
deck1.Add(deck2.Deal(listBox2.SelectedIndex));
}
RedrawDeck(1);
RedrawDeck(2);
}
private List<GameObject> ShuffleList(List<GameObject> ActualList) {
List<GameObject> newList = ActualList;
List<GameObject> outList = new List<GameObject>();
int count = newList.Count;
while (newList.Count > 0) {
int rando = Random.Range(0, newList.Count);
outList.Add(newList[rando]);
newList.RemoveAt(rando);
}
return (outList);
}
usage :
List<GameObject> GetShuffle = ShuffleList(ActualList);
Old post for sure, but I just use a GUID.
Items = Items.OrderBy(o => Guid.NewGuid().ToString()).ToList();
A GUID is always unique, and since it is regenerated every time the result changes each time.
A very simple approach to this kind of problem is to use a number of random element swap in the list.
In pseudo-code this would look like this:
do
r1 = randomPositionInList()
r2 = randomPositionInList()
swap elements at index r1 and index r2
for a certain number of times

Set value to a random property from list

Please check the code below. I am trying to set value to a random property of a int list. Problem is that even after i set 5 to a random list this value getting inserted to that property. What am I doing wrong here?
var TransactionList = new List<int>();
for (int i = 0; i < 59; i++)
{
TransactionList.Add(0);
}
var randTransaction = TransactionList.OrderBy(x => Guid.NewGuid()).FirstOrDefault();
//here i am trying to set 5 value to a random TrnasactionList but this not being set
randTransaction = 5;
Try like below. new Random().Next(0, 59); will return value between 0 and 59. Or you can better set it like new Random().Next(0, TransactionList.Count); for it to be dynamic with list.
new Random().Next(minValue, maxValue); The maxValue for the upper-bound in the Next() method is exclusive—the range includes minValue, maxValue-1, and all numbers in between.
var TransactionList = new List<int>();
for (int i = 0; i < 59; i++)
{
TransactionList.Add(0);
}
// var index = new Random().Next(0, 59);
// Below will work for dynamic length of list.
var index = new Random().Next(0, TransactionList.Count);
TransactionList[index] = 5;
If you don't mind the original list getting sorted you could do this:
class Program
{
static void Main(string[] args)
{
var transactionList = new List<int>();
for (int i = 0; i < 59; i++)
{
//I initialized the list with i instead of 0 to better see sorting in place
transactionList.Add(i);
}
transactionList.Sort(new RandomComparer());
//changed it to 99 to spot it more easily
transactionList[0] = 99;
foreach (var i in transactionList)
Console.WriteLine(i);
}
}
public class RandomComparer : IComparer<int>
{
private Random _random = new Random();
public int Compare(int x, int y)
{
return _random.Next(-1, 2);
}
}
See it in action:
https://dotnetfiddle.net/NKuPdx
randTransaction is "int" data type, which is primitive data type.
if you want to set randTransaction that reflect to it's object, just set the object it self

Generate 4 differents numbers randomly

I am a novice in Xamarin ,
I want to generate randomly 4 numbers which are in a list and this 4 numbers must be different .
In the example below I have a list of Ids and I am trying to pick 4 id randomly in the list and those 4 Ids must be each differents.
Here is my methode, I cannot see how I can continue and make it simple :
public MyWordsList()
{
InitializeComponent();
Dictionary<int, int> WordId = new Dictionary<int, int>();
int u= 0;
// TestAnswer.IsVisible = false;
foreach (var w in mywords)
{
WordId[u] = w.ID;
u++;
}
Random rnd = new Random();
// this is not ok because I can have the same number
word11.Text = WordsList[rnd.Next(1, 20)];
word12.Text = WordsList[rnd.Next(1, 20)];
word13.Text = WordsList[rnd.Next(1, 20)];
word14.Text = WordsList[rnd.Next(1, 20)];
}
If you have a better solution, I will take.
Thanks
You can write a short generic function which picks X amount of random and unique items from a specified collection and returns them:
private static IEnumerable<T> GetUniqueRandomItems<T>(int count, IList<T> allItems)
{
if (new HashSet<T>(allItems).Count < count)
{
throw new ArgumentException(nameof(allItems));
}
Random random = new Random();
HashSet<T> items = new HashSet<T>();
while (items.Count < count)
{
T value = allItems[random.Next(0, allItems.Count)];
items.Add(value);
}
return items;
}
You can later use it like this:
string[] randomIds = GetUniqueRandomItems(4, WordsList).ToArray();
word11.Text = randomIds[0];
word12.Text = randomIds[1];
word13.Text = randomIds[2];
word14.Text = randomIds[3];
call a method like the following:
private int CreateUniqueRandom(int min, int max, ICollection<int> existingNums)
{
var rnd = new Random();
var newNum = rnd.Next(min, max);
while (existingNums.Contains(newNum))
newNum = rnd.Next(min, max);
return newNum;
}
Passing through a list of the numbers that you have created so far
You probably won't need this, but just to show a method of unique random number generation with no duplicate check:
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
var randoms = GenerateRandoms(10, 1, 10).OrderBy(v => v);
foreach (var random in randoms)
{
Console.WriteLine(random);
}
Console.ReadLine();
}
private static int[] GenerateRandoms(int randomCount, int min, int max)
{
var length = max - min + 1;
if (randomCount > length) { throw new ArgumentException($"Cannot generate {randomCount} random numbers between {min} and {max} (inclusive)."); }
var values = new List<int>(length);
for (var i = 0; i < length; i++)
{
values.Insert(i, min + i);
}
var randomGenerator = new Random();
var randoms = new List<int>();
for (var i = 0; i < randomCount; i++)
{
var val = randomGenerator.Next(0, values.Count);
randoms.Add(values[val]);
values.RemoveAt(val);
}
return randoms.ToArray();
}
}
}

Eliminate duplicates from array c#

I'm making a basic Deal or No Deal game, in doing so I have to pick 10 finalists from an array, at random, without repeats.
I have my structure and arrays set out like this
public struct People
{
public string firstname;
public string lastname;
public int age;
}
class Program
{
public static People[] People1 = new People[40];
public static People[] Finalists1 = new People[10];
public static People[] Finalist1 = new People[1];
And my finalists method set out like this
Random rand = new Random();
for (int i = 0; i < Finalists1.Length; i++)
{
num = rand.Next(0, People1.Length);
Finalists1[i].lastname = People1[num].lastname;
Finalists1[i].firstname = People1[num].firstname;
Finalists1[i].age = People1[num].age;
}
How can I eliminate duplicate entries, while maintaining 10 people in the array?
Since initial array doesn't contain duplicates, you can sort it in random order and pick up 10 top items:
Finalists1 = People1
.OrderByDescending(item => 1) // if people have some points, bonuses etc.
.ThenBy(item => Guid.NewGuid()) // shuffle among peers
.Take(10) // Take top 10
.ToArray(); // materialize as an array
If people are selected to the final are not completely random (e.g. contestant can earn points, bonuses etc.) change .OrderByDescending(item => 1), e.g.
.OrderByDescending(item => item.Bonuses)
If you don't want to use Linq, you can just draw Peoples from urn without returning:
private static Random random = new Random();
...
List<People> urn = new List<People>(People1);
for (int i = 0; i < Finalists1.Length; ++i) {
int index = random.Next(0, urn.Count);
Finalists1[i] = urn[index];
urn.RemoveAt(index);
}
You can hold a list or hash set of numbers you have already drawn. Then just roll the dice again to get another random number.
Random rand = new Random();
HashSet<int> drawnNumbers = new HashSet<int>();
for (int i = 0; i < Finalists1.Length; i++)
{
do
{
num = rand.Next(0, People1.Length);
}
while (drawnNumbers.Contains(num));
Finalists1[i] = People1[num];
}
You can change the type of Finalists1 to a HashSet, that does not allow duplicates.
Then change your loop to
while(Finalists1.Length < 10)
{
// random pick from array People1 (you don't need to create a new one)
num = rand.Next(0, People1.Length);
var toAdd = People1[num];
// add to hash-set. Object won't be added, if already existing in the set
Finalists1.Add(toAdd);
}
You probably need to override the Equals method of class People, if you really need to create a new object to add to the hash-set.
You can group people array and select distinct that way.
If you use List you can remove person from the list
`var peopleArray = new People[40];
var peopleCollection = peopleArray.GroupBy(p => new { p.age, p.firstname, p.lastname }).Select(grp => grp.FirstOrDefault()).ToList();
var finalists = new People[10];
var rand = new Random();
for (var i = 0; i < finalists.Length; i++)
{
var index = rand.Next(0, peopleCollection.Count);
var person = peopleCollection[index];
finalists[i].lastname = person.lastname;
finalists[i].firstname = person.firstname;
finalists[i].age = person.age;
peopleCollection.Remove(person);
}
shuffle and take the first 10, for example
People1.Shuffle();
Finalists1= People1.Take(10).ToArray();
you can find shuffle code from StackOverflow or search for "Fisher-Yates shuffle C#" Below methods are taken from This SO Post. Read the answers for more information on why GUID is not used etc..
public static class ThreadSafeRandom
{
[ThreadStatic] private static Random Local;
public static Random ThisThreadsRandom
{
get { return Local ?? (Local = new Random(unchecked(Environment.TickCount * 31 + Thread.CurrentThread.ManagedThreadId))); }
}
}
static class MyExtensions
{
public static void Shuffle<T>(this IList<T> list)
{
int n = list.Count;
while (n > 1)
{
n--;
int k = ThreadSafeRandom.ThisThreadsRandom.Next(n + 1);
T value = list[k];
list[k] = list[n];
list[n] = value;
}
}
}
Swap each selected element in People1 to with the end of the array, and decrement an end-of-array index so that you're only selecting from what's left on the next iteration.
People tempPerson = new People;
int lastElem = People1.length - 1;
for (int i = 0; i < Finalists1.Length; i++)
{
num = rand.Next(0, lastElem + 1);
Finalists1[i] = People1[num];
//swap last entry in People1 with People1[num]
tempPerson = People1[num];
People1[num] = People1[lastElem];
People1[lastElem] = tempPerson;
lastElem--;
}
Sorry if there's a syntax error, I'm mostly using Java and C# these days.
BTW You don't have to set the fields individually since each array stores objects of type Person.

Sort a collection of randomly generated numbers

I am creating a random number generator in c#
I generate the numbers as so
Random RandomClass = new Random();
Num1.text = RandomClass.Next(1,49).ToString();
Num2.text = RandomClass.Next(1,49).ToString();
Num3.text = RandomClass.Next(1,49).ToString();
Num4.text = RandomClass.Next(1,49).ToString();
Num5.text = RandomClass.Next(1,49).ToString();
Num6.text = RandomClass.Next(1,49).ToString();
The user clicks a button and the numbers are generated, what I want is for there to be a button which can sort the numbers, so for example smallest to lowest.
Could I turn the numbers generated into an array and call .ToArray and then sort from there? I am unsure how to group the random numbers together to then call a sorting method on them.
Just add the random numbers to a list and sort them.
Random RandomClass = new Random();
List<int> list = new List<int>();
for (int i = 0; i < 10; i++)
list.Add(RandomClass.Next(1, 49));
list.Sort();
// If you need to reverse it...
list.Reverse();
If you are comparing to a List<string> you will need to write a comparer.
Example:
private static int CompareValues(string x, string y)
{
if (x == null)
return y == null ? 0 : -1;
else
{
if (y == null)
return 1;
else
{
int left = Int32.Parse(x);
int right = Int32.Parse(y);
if (left > right)
return 1;
else if (left < right)
return -1;
else
return 0;
}
}
}
Then to use it, pass it as argument to the Sort() method. This will now be used as a custom compare to handle the integer values and sort them properly.
list.Sort(CompareValues);
If you store the random numbers in a list, you could sort (or manipulate them in a number of ways) easily using Linq. Assuming your method returns random integers:
var myRandomNumbers = new List<int>
{
RandomClass.Next(1,49),
RandomClass.Next(1,49)
};
var mySortedRandomNumbers = myRandomNumbers.OrderByDescending(x => x).ToList();
Of course, if you're always calling RandomClass.Next(1,49) you could optimize with a loop and use .Add() on the list.
Here's a solution that generates random numbers and saves them for later.
//fields
private readonly Random _random = new Random();
private readonly List<int> _randomNumbers = new List<int>();
public void SomeEvent(object sender, EventArgs e)
{
_randomNumbers.Clear();
Num1.text = GetRandom().First().ToString();
Num2.text = GetRandom().First().ToString();
Num3.text = GetRandom().First().ToString();
Num4.text = GetRandom().First().ToString();
Num5.text = GetRandom().First().ToString();
Num6.text = GetRandom().First().ToString();
}
public void SortRandomNumbers(object sender, EventArgs e)
{
var sortedRandoms = _randomNumbers;
sortedRandoms.Sort();
//do stuff with sortedRandoms
}
// Gets a random value and caches it
private IEnumerable<int> GetRandom()
{
while(true)
{
var value = _random.Next(1, 49);
_randomNumbers.Add(value);
yield return _randomNumbers.Last();
}
}
If you always have six fields Num1 - Num6, you could add their content to a List<int>, sort them by using .OrderBy() and fill them up again using the ordered list.
List<int> nums = new List<int>();
nums.Add(Convert.ToInt32(Num1.text));
.
.
nums.Add(Convert.ToInt32(Num6.text));
nums = nums.OrderBy(num => num).ToList(); //or OrderByDescending
Num1.text = nums[0];
.
.
Num6.text = nums[5];
Yes, you could use an Array:
RandomClass.Next(1,49).ToString();
ArrayList numbers = new ArrayList();
for (int i = 0; i < 10; i++)
numbers[i] = RandomClass.Next(1,49).ToString();
numbers.Sort();

Categories

Resources