Random objects to a list without repetition - c#

I have a little problem over here. I have a list of questions KlausimuList and i have to form another list Atsitiktinis witch would be a random length and would have random questions taken from KlausimuList. My method works, but the problem is - questions are duplicating. Could you please write me a code where they don't? I have an idea of making a seperate int array of indexes of questions i already added, and then each time check if that question already is in that list. If it does - genererate a new number, but i just don't know how to write the code for this thing :D. Thanks in advice. Code is in c#.
static void FormuotiAtsisiktini(List<Klausimas> KlausimuList, ref List<Klausimas> Atsitiktinis)
{
Random kiek = new Random();
int kiekis = kiek.Next(1, KlausimuList.Count);
for (int i = 0; i < kiekis; i++)
Atsitiktinis.Add(KlausimuList[kiek.Next(1, KlausimuList.Count)]);
}

You could use HashSet to avoid duplicates. Add method on HashSet returns false when try adding duplicate item.
static void FormuotiAtsisiktini(List<Klausimas> KlausimuList, ref List<Klausimas> Atsitiktinis)
{
Random kiek = new Random();
int kiekis = kiek.Next(1, KlausimuList.Count);
HashSet<Klausimas> hashset= new HashSet<Klausimas>();
for (int i = 0; i < kiekis;)
{
i+= hashset.Add(KlausimuList[kiek.Next(1, KlausimuList.Count)])? 1:0; // returns true when successfully added.
}
Atsitiktinis = hashset.ToList();
}

This should work. It creates a copy of the original list and removes the already taken items from it:
static List<Klausimas> FormuotiAtsisiktini(List<Klausimas> KlausimuList)
{
Random kiek = new Random();
List<Klausimas> source = new List<Klausimas>(KlausimuList);
List<Klausimas> result = new List<Klausimas>();
int kiekis = kiek.Next(1, KlausimuList.Count);
for (int i = 0; i < kiekis; i++)
{
var match = source[kiek.Next(0, source.Count - 1)];
result.Add(match);
source.Remove(match);
}
return result;
}

What you are describing is called sampling without replacement, and a solution to that is provided in this SO post. Furthermore, to ensure that you are actually adding duplicates to your collection, consider using a HashSet instead of a List.

Related

How to solve argument out of range exceptions [duplicate]

This question already has answers here:
ArgumentOutOfRangeException on initialized List
(1 answer)
How to initialize a List<T> to a given size (as opposed to capacity)?
(16 answers)
Closed 4 years ago.
So I've been looking around for quite a while to try and find a solution to this.
I've been trying to make a card game and am stuck at a section in which I create a cad along with its properties. i decided to make it in the form of an array. The code looks like:
(not sure what happened with these first ones)
string[] dogs = System.IO.File.ReadAllLines(#"C:\Users\corin\Documents\C# coding\dogs.txt");
int individual = totalCards / 2;
Random r = new Random();
int Cards = totalCards / 2;
List<List<int>> playerCards = new List<List<int>>(Cards);
for (int x = 0; x < (Cards-2); x++)
{
playerCards[0].Add(Int32.Parse(dogs[x]));//Cards
playerCards[1].Add(r.Next(1, 6));//Drool
playerCards[2].Add(r.Next(1, 101));//Exercise
playerCards[3].Add(r.Next(1, 11));//Intelligence
playerCards[4].Add(r.Next(1, 11));//Friendliness
}
No errors are raised before I run the code but when I try it an Argument out of range exception occurs for the line: playerCards[0].Add(Int32.Parse(dogs[x]));
I tried removing it and the same error occured for the next line. I'm not sure what I've done wrong and have tried to find a solution for quite some time. If anyone has any tips or answers that would be great.
Thanks
try this :
string[] dogs = System.IO.File.ReadAllLines(#"C:\Users\corin\Documents\C# coding\dogs.txt");
int individual = totalCards / 2;
Random r = new Random();
int Cards = totalCards / 2;
List<List<int>> playerCards = new List<List<int>>();
//the missing piece
for (int i = 0; i < (Cards ); i++)
{
playerCards.add(new List<int>());
}
for (int x = 0; x < (Cards-2); x++)
{
playerCards[0].Add(Int32.Parse(dogs[x]));//Cards
playerCards[1].Add(r.Next(1, 6));//Drool
playerCards[2].Add(r.Next(1, 101));//Exercise
playerCards[3].Add(r.Next(1, 11));//Intelligence
playerCards[4].Add(r.Next(1, 11));//Friendliness
}
In addition to the previous answers: new List<List<int>>(Cards) doesn't do what you think it does. It sets capacity, not elementCount (or whatever it's called). When bounds are checked, elementCount is used, not capacity. capacity is useful when you have a good idea how many elements you have, to avoid reallocations and don't waste space.
So yes, before accessing by index you should add elements into the list manually.

List or better Algorithm for random C# - Unity [duplicate]

What is the best way to randomize an array of strings with .NET? My array contains about 500 strings and I'd like to create a new Array with the same strings but in a random order.
Please include a C# example in your answer.
The following implementation uses the Fisher-Yates algorithm AKA the Knuth Shuffle. It runs in O(n) time and shuffles in place, so is better performing than the 'sort by random' technique, although it is more lines of code. See here for some comparative performance measurements. I have used System.Random, which is fine for non-cryptographic purposes.*
static class RandomExtensions
{
public static void Shuffle<T> (this Random rng, T[] array)
{
int n = array.Length;
while (n > 1)
{
int k = rng.Next(n--);
T temp = array[n];
array[n] = array[k];
array[k] = temp;
}
}
}
Usage:
var array = new int[] {1, 2, 3, 4};
var rng = new Random();
rng.Shuffle(array);
rng.Shuffle(array); // different order from first call to Shuffle
* For longer arrays, in order to make the (extremely large) number of permutations equally probable it would be necessary to run a pseudo-random number generator (PRNG) through many iterations for each swap to produce enough entropy. For a 500-element array only a very small fraction of the possible 500! permutations will be possible to obtain using a PRNG. Nevertheless, the Fisher-Yates algorithm is unbiased and therefore the shuffle will be as good as the RNG you use.
If you're on .NET 3.5, you can use the following IEnumerable coolness:
Random rnd=new Random();
string[] MyRandomArray = MyArray.OrderBy(x => rnd.Next()).ToArray();
Edit: and here's the corresponding VB.NET code:
Dim rnd As New System.Random
Dim MyRandomArray = MyArray.OrderBy(Function() rnd.Next()).ToArray()
Second edit, in response to remarks that System.Random "isn't threadsafe" and "only suitable for toy apps" due to returning a time-based sequence: as used in my example, Random() is perfectly thread-safe, unless you're allowing the routine in which you randomize the array to be re-entered, in which case you'll need something like lock (MyRandomArray) anyway in order not to corrupt your data, which will protect rnd as well.
Also, it should be well-understood that System.Random as a source of entropy isn't very strong. As noted in the MSDN documentation, you should use something derived from System.Security.Cryptography.RandomNumberGenerator if you're doing anything security-related. For example:
using System.Security.Cryptography;
...
RNGCryptoServiceProvider rnd = new RNGCryptoServiceProvider();
string[] MyRandomArray = MyArray.OrderBy(x => GetNextInt32(rnd)).ToArray();
...
static int GetNextInt32(RNGCryptoServiceProvider rnd)
{
byte[] randomInt = new byte[4];
rnd.GetBytes(randomInt);
return Convert.ToInt32(randomInt[0]);
}
You're looking for a shuffling algorithm, right?
Okay, there are two ways to do this: the clever-but-people-always-seem-to-misunderstand-it-and-get-it-wrong-so-maybe-its-not-that-clever-after-all way, and the dumb-as-rocks-but-who-cares-because-it-works way.
Dumb way
Create a duplicate of your first array, but tag each string should with a random number.
Sort the duplicate array with respect to the random number.
This algorithm works well, but make sure that your random number generator is unlikely to tag two strings with the same number. Because of the so-called Birthday Paradox, this happens more often than you might expect. Its time complexity is O(n log n).
Clever way
I'll describe this as a recursive algorithm:
To shuffle an array of size n (indices in the range [0..n-1]):
if n = 0
do nothing
if n > 0
(recursive step) shuffle the first n-1 elements of the array
choose a random index, x, in the range [0..n-1]
swap the element at index n-1 with the element at index x
The iterative equivalent is to walk an iterator through the array, swapping with random elements as you go along, but notice that you cannot swap with an element after the one that the iterator points to. This is a very common mistake, and leads to a biased shuffle.
Time complexity is O(n).
This algorithm is simple but not efficient, O(N2). All the "order by" algorithms are typically O(N log N). It probably doesn't make a difference below hundreds of thousands of elements but it would for large lists.
var stringlist = ... // add your values to stringlist
var r = new Random();
var res = new List<string>(stringlist.Count);
while (stringlist.Count >0)
{
var i = r.Next(stringlist.Count);
res.Add(stringlist[i]);
stringlist.RemoveAt(i);
}
The reason why it's O(N2) is subtle: List.RemoveAt() is a O(N) operation unless you remove in order from the end.
You can also make an extention method out of Matt Howells. Example.
namespace System
{
public static class MSSystemExtenstions
{
private static Random rng = new Random();
public static void Shuffle<T>(this T[] array)
{
rng = new Random();
int n = array.Length;
while (n > 1)
{
int k = rng.Next(n);
n--;
T temp = array[n];
array[n] = array[k];
array[k] = temp;
}
}
}
}
Then you can just use it like:
string[] names = new string[] {
"Aaron Moline1",
"Aaron Moline2",
"Aaron Moline3",
"Aaron Moline4",
"Aaron Moline5",
"Aaron Moline6",
"Aaron Moline7",
"Aaron Moline8",
"Aaron Moline9",
};
names.Shuffle<string>();
Just thinking off the top of my head, you could do this:
public string[] Randomize(string[] input)
{
List<string> inputList = input.ToList();
string[] output = new string[input.Length];
Random randomizer = new Random();
int i = 0;
while (inputList.Count > 0)
{
int index = r.Next(inputList.Count);
output[i++] = inputList[index];
inputList.RemoveAt(index);
}
return (output);
}
Randomizing the array is intensive as you have to shift around a bunch of strings. Why not just randomly read from the array? In the worst case you could even create a wrapper class with a getNextString(). If you really do need to create a random array then you could do something like
for i = 0 -> i= array.length * 5
swap two strings in random places
The *5 is arbitrary.
public static void Shuffle(object[] arr)
{
Random rand = new Random();
for (int i = arr.Length - 1; i >= 1; i--)
{
int j = rand.Next(i + 1);
object tmp = arr[j];
arr[j] = arr[i];
arr[i] = tmp;
}
}
Generate an array of random floats or ints of the same length. Sort that array, and do corresponding swaps on your target array.
This yields a truly independent sort.
Ok, this is clearly a bump from my side (apologizes...), but I often use a quite general and cryptographically strong method.
public static class EnumerableExtensions
{
static readonly RNGCryptoServiceProvider RngCryptoServiceProvider = new RNGCryptoServiceProvider();
public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> enumerable)
{
var randomIntegerBuffer = new byte[4];
Func<int> rand = () =>
{
RngCryptoServiceProvider.GetBytes(randomIntegerBuffer);
return BitConverter.ToInt32(randomIntegerBuffer, 0);
};
return from item in enumerable
let rec = new {item, rnd = rand()}
orderby rec.rnd
select rec.item;
}
}
Shuffle() is an extension on any IEnumerable so getting, say, numbers from 0 to 1000 in random order in a list can be done with
Enumerable.Range(0,1000).Shuffle().ToList()
This method also wont give any surprises when it comes to sorting, since the sort value is generated and remembered exactly once per element in the sequence.
Random r = new Random();
List<string> list = new List(originalArray);
List<string> randomStrings = new List();
while(list.Count > 0)
{
int i = r.Random(list.Count);
randomStrings.Add(list[i]);
list.RemoveAt(i);
}
Jacco, your solution ising a custom IComparer isn't safe. The Sort routines require the comparer to conform to several requirements in order to function properly. First among them is consistency. If the comparer is called on the same pair of objects, it must always return the same result. (the comparison must also be transitive).
Failure to meet these requirements can cause any number of problems in the sorting routine including the possibility of an infinite loop.
Regarding the solutions that associate a random numeric value with each entry and then sort by that value, these are lead to an inherent bias in the output because any time two entries are assigned the same numeric value, the randomness of the output will be compromised. (In a "stable" sort routine, whichever is first in the input will be first in the output. Array.Sort doesn't happen to be stable, but there is still a bias based on the partitioning done by the Quicksort algorithm).
You need to do some thinking about what level of randomness you require. If you are running a poker site where you need cryptographic levels of randomness to protect against a determined attacker you have very different requirements from someone who just wants to randomize a song playlist.
For song-list shuffling, there's no problem using a seeded PRNG (like System.Random). For a poker site, it's not even an option and you need to think about the problem a lot harder than anyone is going to do for you on stackoverflow. (using a cryptographic RNG is only the beginning, you need to ensure that your algorithm doesn't introduce a bias, that you have sufficient sources of entropy, and that you don't expose any internal state that would compromise subsequent randomness).
This post has already been pretty well answered - use a Durstenfeld implementation of the Fisher-Yates shuffle for a fast and unbiased result. There have even been some implementations posted, though I note some are actually incorrect.
I wrote a couple of posts a while back about implementing full and partial shuffles using this technique, and (this second link is where I'm hoping to add value) also a follow-up post about how to check whether your implementation is unbiased, which can be used to check any shuffle algorithm. You can see at the end of the second post the effect of a simple mistake in the random number selection can make.
You don't need complicated algorithms.
Just one simple line:
Random random = new Random();
array.ToList().Sort((x, y) => random.Next(-1, 1)).ToArray();
Note that we need to convert the Array to a List first, if you don't use List in the first place.
Also, mind that this is not efficient for very large arrays! Otherwise it's clean & simple.
This is a complete working Console solution based on the example provided in here:
class Program
{
static string[] words1 = new string[] { "brown", "jumped", "the", "fox", "quick" };
static void Main()
{
var result = Shuffle(words1);
foreach (var i in result)
{
Console.Write(i + " ");
}
Console.ReadKey();
}
static string[] Shuffle(string[] wordArray) {
Random random = new Random();
for (int i = wordArray.Length - 1; i > 0; i--)
{
int swapIndex = random.Next(i + 1);
string temp = wordArray[i];
wordArray[i] = wordArray[swapIndex];
wordArray[swapIndex] = temp;
}
return wordArray;
}
}
int[] numbers = {0,1,2,3,4,5,6,7,8,9};
List<int> numList = new List<int>();
numList.AddRange(numbers);
Console.WriteLine("Original Order");
for (int i = 0; i < numList.Count; i++)
{
Console.Write(String.Format("{0} ",numList[i]));
}
Random random = new Random();
Console.WriteLine("\n\nRandom Order");
for (int i = 0; i < numList.Capacity; i++)
{
int randomIndex = random.Next(numList.Count);
Console.Write(String.Format("{0} ", numList[randomIndex]));
numList.RemoveAt(randomIndex);
}
Console.ReadLine();
Could be:
Random random = new();
string RandomWord()
{
const string CHARS = "abcdefghijklmnoprstuvwxyz";
int n = random.Next(CHARS.Length);
return string.Join("", CHARS.OrderBy(x => random.Next()).ToArray())[0..n];
}
Here's a simple way using OLINQ:
// Input array
List<String> lst = new List<string>();
for (int i = 0; i < 500; i += 1) lst.Add(i.ToString());
// Output array
List<String> lstRandom = new List<string>();
// Randomize
Random rnd = new Random();
lstRandom.AddRange(from s in lst orderby rnd.Next(100) select s);
private ArrayList ShuffleArrayList(ArrayList source)
{
ArrayList sortedList = new ArrayList();
Random generator = new Random();
while (source.Count > 0)
{
int position = generator.Next(source.Count);
sortedList.Add(source[position]);
source.RemoveAt(position);
}
return sortedList;
}

Create array without duplicates c#

So this is my code right now, and I need help so it won't makes duplicates. I need this for school so if you could explain a little bit too it would be helpful. Btw don't care about the comments it's on Swedish
int temp;
int[] myArray = new int[20]; // Array med 20 tal
Random random = new Random(); // Skapar metoden "Random"
for (int i = 0; i < myArray.Length; i++) // Forloop med 20 positioner
{
myArray[i] = random.Next(1, 100); // Ger random värden till dessa 20 positionerna
for (int j = 0; j < myArray.Length; j++)
{
if (myArray[i] > myArray[j]) // Array [i] större än Array [j]
{
//temp = myArray[j];
//myArray[j] = myArray[i];
//myArray[i] = temp;
}
}
Console.Write(myArray[i] + " ");
}
you can try linq to .Distinct() and to convert it to array use .ToArray()
var s = { 5, 7, 7, 4, 3};
var q = s.Distinct().ToArray();
At it's simplest, it looks like you probably want to
private static Random rng = new Random(); //class level definition
var myArray = Enumerable.Range(1, 20).OrderBy(X => rng.Next()).ToArray();
Alternatively, if this is for school and you need to justify your code... fill an array with the numbers 1 to 20, then use a Fisher-Yates shuffle to randomise the order of the array.
See: https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle
Since the array has exatly the size of the random value range (which is 20), you will get every number exactly once. It's easiest to create every number once using Enumerable.Range and only change the order in which they appear.
Changing the order can be done by OrderBy(), while random is used here.
This is all based on IEnumerable<T>. So it needs to be put into an array, which is simply done by calling ToArray().
public int[] RandomlyOrderedValues()
{
Random random = new Random();
return Enumerable.Range(1, 20).OrderBy(x => random.Next()).ToArray();
}
I'm not your teacher but hope you still play around by yourself, read the docs and finally express it in your own words.
Changed question, now the random range is larger than the array size.
It's always best to work with IEnumerable<T>, there you get the most powerful tools.
// let's create inifite number of random values:
// note that the Random instance needs to be created only once,
// so it's put into a field.
private Random random = new Random();
public IEnumerable<int> InfiniteRandomValues()
{
while (true)
{
yield return random.Next(1, 100);
}
}
public int[] GetUniqueRandomValues(int numberOfValues)
{
return InfiniteRandomValues()
// only uninque values
.Distinct()
// generate the requested number of distinct values
.Take(numberOfValues)
// put it into an array.
.ToArray();
}
How does it work? When you create random values, you don't know how many it will be, because you cannot know how many duplicates it will create. A generator for an infinite number of values has certainly enough values. Think of it as a factory. Only when the IEnumerable is iterated, the values are created.
This is called "deferred execution". Only when you iterate the IEnumerable, the values are requested by the source.
Distinct works like this. It returns only as many distinct values as are requested by its caller.
Which is Take. This one reduces the number of items that are taken, but still doesn't iterate itselves.
ToArray finally iterates its source and pulls as many values as there are. Read it backwards now: It takes all values from Take, which returns 20. Itselves it takes 20 values from Distinct, which iterates its source until it got 20 distinct values. Distinct takes its values from the InifiteRandomNumbers factory and can take as many as it needs.
When you finally understand how these things work, you can use it quite intuitively.
Another, more classic implemenation
private int[] GetRandomValues()
{
Random random = new Random();
int[] values = new int[20];
for(int i = 0; i < 20; i++)
{
// create random values until you found a distinct oune.
int nextValue;
do
{
nextValue = random.Next(1, 100);
} while (ContainsValue(values, i, nextValue))
values[i] = nextValue;
}
return values;
}
// When adding the values to a List instead of an array, it would be
// much easier, but need copying the vlaues to the array at the end.
// When using the array directly, you have to know which values you
// already generated, because it's initialized with zero.
// This method checks wether the value is in the array within
// the items until endIndex.
private bool ContainsValue(int[] values, int endIndex, int valueToFind)
{
// simple linq way:
// return values.Take(endIndex).Contains(valueToFind);
// classic way:
for(int i = 0; i < endIndex; i++)
{
if (values[i] = valueToFind) return true;
}
return false;
}

How do I set parts of an array to a random value in C#?

I'm new to programming so please bear with me!
I am trying to set the parts of an array to random values, but whenever I run the program it sets all parts of the array to the same value. I want them all to be different.
Here is my code:
int[] hello_array = new int[10];
Console.WriteLine("Here");
Random rndm = new Random();
for (int j = 0; j < hello_array.Length; j++)
{
hello_array[j] = rndm.Next(99);
}
Console.WriteLine("Now Here");
for (int i = 0; i < hello_array.Length; i++)
{
Console.WriteLine("hahahaha look at this " + hello_array[0]);
I'm probably completely missing it, but I can't tell what's wrong with my code! Can someone please tell me how I would make it so that all ten parts of the array generate different random numbers?
Change this:
Console.WriteLine("hahahaha look at this " + hello_array[0]);
to this:
Console.WriteLine("hahahaha look at this " + hello_array[i]);
You were printing the same element in the array on every loop.
With the same number of lines, you could use some of the newer C# features to accomplish the same result (but without all the messy details).
You'd define a generic method that takes two parameters: a lambda expression (for instance, () => random.Next(99)) and the number of elements to generate. Inside the method, you'd use the yield keyword to return a new element generated by the factory.
Random random = new Random();
foreach (var element in Generate(() => random.Next(99), 10))
{
Console.WriteLine(element);
}
public static IEnumerable<T> Generate<T>(Func<T> factory, int elements)
{
for (int generated = 0; generated < elements; generated++)
{
yield return factory();
}
}

Which collection type to use?

I have a scenario where I have a list of classes, and I want to mix up the order. For example:
private List<Question> myQuestions = new List<Question>();
So, given that this is now populated with a set of data, I want to mix up the order. My first thought was to create a collection of integers numbered from 1 to myQuestions.Count, assign one at random to each question and then loop through them in order; however, I can’t seem to find a suitable collection type to use for this. An example of what I mean would be something like this:
for (int i = 0; i <= myQuestions.Count -1; i++)
tempCollection[i] = myQuestions[rnd.Next(myQuestions.Count-1)];
But I’m not sure what tempCollection should be – it just needs to be a single value that I can remove as I use it. Does anyone have any suggestions as to which type to use, or of a better way to do this?
I suggest you copy the results into a new List<Question> and then shuffle that list.
However, I would use a Fisher-Yates shuffle rather than the one you've given here. There are plenty of C# examples of that on this site.
For example, you might do:
// Don't create a new instance of Random each time. That's a detail
// for another question though.
Random rng = GetAppropriateRandomInstanceForThread();
List<Question> shuffled = new List<Question>(myQuestions);
for (int i = shuffled.Count - 1; i > 0; i--)
{
// Swap element "i" with a random earlier element it (or itself)
int swapIndex = rng.Next(i + 1);
Question tmp = shuffled[i];
shuffled[i] = shuffled[swapIndex];
shuffled[swapIndex] = tmp;
}
You could use Linq and order by a random value:
List<string> items = new List<string>();
items.Add("Foo");
items.Add("Bar");
items.Add("Baz");
foreach (string item in items.OrderBy(c => Guid.NewGuid()))
{
Console.WriteLine(item);
}
temp Collection should be same type as myQuestions.
I would also suggest a change in your code:
for (int i = 0; i <= myQuestions.Count -1; i++)
to
for (int i = 0; i < myQuestions.Count; i++)
Does the same thing, but this is how most programers do it so it will make your code simpler to read.

Categories

Resources