I'm looking for a way to randomize a List using a seed. What I want to achieve by this is controlled randomization. In other words to make sure that a list is always randomized in the same order if I use the same seed to do it.
I'm currently using this code:
string arbitrarySeed = "someValue";
System.Random random = new System.Random(BitConverter.ToInt32(Encoding.ASCII.GetBytes(arbitrarySeed), 0));
List<object> randomizedOptions = items?.OrderBy(o => random.Next()).ToList();
Which seems a bit overcomplicated so I'm looking for a more elegant way to handle this.
I know that randomizing is this way is not actually very random, but I don't need it to be true randomness. Something that comes close will do fine.
Depending on how "consistent" you need the generated series to be, you could use string.GetHashCode:
string arbitrarySeed = "someValue";
System.Random random = new System.Random(arbitrarySeed.GetHashCode());
List<object> randomizedOptions = items?.OrderBy(o => random.Next()).ToList();
GetHashCode is not guaranteed to be consistent across .NET versions or implementations (e.g. Linux, Windows, macOS) but if you need localized consistency it may work for you.
Also note that BitConverter.ToInt32 will only take 4 bytes of the array you pass in, so "someValue" and "someValue2" would give you the same seed value.
Related
I am using this code to pick a random element from a list:
var rand = new Random();
var i = rand.Next(words.Count);
keyword = words[i].keyword;
Is this the optimal way to do this or is there a better way that I could employ? What I am particularly concerned about is will this be completely random?
If you are going to create more than one random number, you should keep the Random instance and reuse it. If you create new instances too close in time, they will produce the same series of random numbers as the random generator is seeded from the system clock.
Every time you do new Random() it is initialized . This means that in a tight loop you get the same value lots of times. You should keep a single Random instance and keep using Next on the same instance.
Hope this helps!!!
It will be absymally un-random, you must not create a new Random instance each time you need a number. Doing that completely ruins the statistical properties of the generator.
Even then you will not achieve perfect randomness (you need external hardware for that), but it ought to satisfy all the principal properties of randomness.
Put this line for single time initialization: var rand = new Random();
Use below code to generate new number each time.
var i = rand.Next(words.Count);
keyword = words[i].keyword;
Hope it will help you.
I am familiar with Random and RNGCryptoServiceProvider and how they can be used to generate random numbers in C#.
But I am also aware of the following method:
int start = 10;
int end = 50;
Enumerable.Range(start, end).OrderBy(o => Guid.NewGuid()).Take(5);
Given the streaming power of LINQ and the given thread-safety of this method (as opposed to using a shared Random) I cannot find a reason not to use this method.
What am I missing other than performance?
The Guid class is intended to create unique numbers, not random ones.
There is no guarantee that you will get a uniform distribution. It will certainly not qualify as safe for Encryption related tasks.
Just use the class that is most appropriate for a certain task. Random for fast pseudo random data and the RNGCryptoServiceProvider for security.
The Linq approach is a hack. When you have a Threading problem, make it thread-safe in an established manner.
If you want to use linq interface, I would suggest something like this:
public IEnumerable<int> GetRandomSequence(int start, int end)
{
var generator = new Random();
while (true)
yield return generator.Next(start, end);
}
And then
var randomSequence = GetRandomSequence(10, 50).Take(5);
But it would be safer to use a counter instead of "while (true)" to avoid endless cycles in cases like this:
var sequence = GetRandomSequence();
var someOtherSequence = sequence.Skip(5); // here we forget to call Take, Zip, TakeWhile etc.
// some code
var someVar = someOtherSequence.ToList(); // endless call here
var someOtherVar = someOtherSequence.Join( ... ) // and here
The problem (or possibly benefit?) of your technique is that it will not repeat any number in the range.
In a true random-set, you could reasonably see a number repeated on occasion.
Example: {12, 46, 12, 27, 12} should be valid output.
With your method, you'll never see 12 repeated.If you want the numbers 10-50 returned in a random order, but each one only once, then you really want a Shuffling Algorithm.
I'm creating a program which creates several panels with randomly determined colors which will be incremented/decremented by some random constant every 20 milliseconds or so to create a smooth, undulating color. For this, I've just been using the Next(int) method of the Random class. For a single instance, this works perfectly--every time I run the program, I get different colors changing at different rates. The problem comes when I try to create multiple panels--most, if not all, come out looking and behaving identically to each other, implying that all of the randomly generated numbers were identical. I'm assuming that this is a result of generating all of the pseudorandom numbers in rapid succession, causing all of them to be based on the same seed.
Is there a better way than using the Random class to generate random integers in rapid succession to ensure that they're not identical? If there isn't any way already built into C#, is there any straightforward way to develop a pseudorandom number generator (bearing in mind that this is my first foray into using C#)?
Do not use multiple instances of the Random Class using the default constructor. If they all are initialized within the same time slice they will all have the same seed and will all generate the same sequence of random numbers, use the constructor that you can pass in a seed and pass a different seed to each instance.
Random rand0, rand1, rand2;
void init()
{
int baseSeed = (int) DateTime.Now.Ticks;
rand0 = new Random(baseSeed);
rand1 = new Random(baseSeed + 1);
rand2 = new Random(baseSeed + 2);
}
Also you only need one object per thread, use the same Random object for all of the panels if they are all on the same thread.
Random is fine if you don't need cryptographically secure random numbers - but chances are you're creating a new instance every time you need a number, rather than using one instance throughout.
When you create a new instance of Random it will take "the current time" as the seed - so if you create two in quick succession, you'll end up with two instances with the same seed and therefore the same numbers (when you use the same calls).
It's generally better to use a single instance of Random - or rather, one per thread, as it's not thread-safe.
See my article on the topic for various approaches.
If you have multiple instances of the Random class that are producing identical series of random numbers, then you must be creating each instance using the same seed. For example:
The most likely explanation for that is that you are creating them all like this:
var rng = new Random();
and creating each instance at the same point in time. This constructor uses the current time to seed the RNG and if you create them all at the same point in time, they will all be seeded with the same time.
Solve the problem by creating each instance with a different seed. Or create a single RNG and share it between all panels.
I prefer RNGCryptoServiceProvider. It is roughly as fast as Random and tends to produce more unique values in my informal testing. You also avoid any undesirable behaviors pertaining to seeding (such as others are describing).
However, you can't guarantee uniqueness (otherwise it wouldn't be random). You can use a database if you need to permanently track unique values (which it doesn't sound like you wish to do) or a Dictionary where the random value is the key if you just care about generating a set of unique numbers in memory. If the key already exists, you reject the value and generate another one.
using System.Security.Cryptography;
...
RNGCryptoServiceProvider crypto = new RNGCryptoServiceProvider();
byte[] bytes = new byte[8];
crypto.GetBytes( bytes );
long value = BitConverter.ToInt64( bytes, 0 );
As mentioned above, you can use a single instance of the random class. However, if for some reason this isn't desirable (i.e. you want to run multiple threads and don't want any contention), then you can use multiple instances as long as you initialize the seed for each generator to a random or pseudo-randomly generated seed.
For this initial seed generation, you will need to use the same Random generator.
I know C# has the Random class and probably a few classes in LINQ to do this, but if I was to write my own code to randomly select an item from a collection without using any built in .NET objects, how would this be done?
I can't seem to nail the logic required for this - how would I tell the system when to stop an iteration and select the current value - at random?
EDIT: This is a hypothetical question. This is not related to a production coding matter. I am just curious.
Selecting a random element from a collection can be done as follows.
Random r = new Random();
int randomIndex = r.Next(0, myCollection.Size -1);
var randomCollectionItem = myCollection[randomIndex];
Unless you have a VERY good reason, writing your own random generator is not necessary.
My advice to you is DON'T DO IT. Whatever reason you think you may have for not wanting to use the built-in library, I am pretty sure you misunderstood something. Please go back to the drawing board.
All of the advice above is technically accurate, but is kind of like giving a chemistry textbook to someone who wants to refine his own oil to use in his car.
There are many pseudo-random number generators. They aren't truly random, but they come at different quality, distinguished by their statistical and sequential properties and what purpose they are applicable for.
It very much depends on "how random you need it". If it just needs to "look random to a human", simple generators look like that:
rnd = seed; // some starting value
rnd = (a * rnd + b) % c; // next value
...
For well chosen values of a, b, and cthese generators are ok for simple statistical tests. A detailed discussion and common values for these you find here.
One interesting approach is to collect as much "external" data as possible - like time between keypresses, mouse movements, duration of disk reads etc. -, and use an algorithm that accumulates randomness while discarding dependency. That is mathematically tricky though (IIRC not long ago a critical attack surfaced based on one of these not being as random as thought).
Only a very few special applications use a truly random external hardware source - anything between a open-imput amplifier and radioactive decay.
You need to use a seed, something semi random provided by the computer itself.
Maybe use very fine resolution time and use the last couple microseconds when the method is called. That should be random enough to generate anything from 00 to 99, you can then go from there.
It sounds like your problem isn't in calculating a random number, but in how to use that random number to select an item from a list. Assuming you can create a random number somehow, all you need to do is use it as the argument to the list's indexer.
int index = customRandomGenerator.Next();
var selection = items[index];
Assuming that your presupposition about having to iterate through the list is correct (or the collection doesn't have an indexer) then you could do:
int index = customRandomGenerator.Next();
Item selection = null;
for (int i = 0; i < items.Length; i++)
{
if (i == index)
{
selection = items[i];
break;
}
}
The only true "cryptographically strong" random number generator in the .Net Framework is in System.Cryptography.RandomNumberGenerator - run this through Reflector to see what is does? Looking at your problem you would need a to know the Count of the collection otherwise you may never retrieve an item - you would need to specify a start and end value to draw random numbers from - the Random class would work best - pop it through Reflector.
Well, I never thought about implementing that myself as it seems like reinventing the wheel but you may have a look on this wikipedia article, hope it helps you do what you want
Random Number Generator
I've just started learning C# and in the introduction to arrays they showed how to establish a variable as an array but is seems that one must specify the length of the array at assignment, so what if I don't know the length of the array?
Arrays must be assigned a length. To allow for any number of elements, use the List class.
For example:
List<int> myInts = new List<int>();
myInts.Add(5);
myInts.Add(10);
myInts.Add(11);
myInts.Count // = 3
Use List<> to build up an 'array' of unknown length.
Use List<>.ToArray() to return a real array, and not a List.
var list = new List<int>();
list.Add(1);
list.Add(2);
list.Add(3);
var array = list.ToArray();
A little background information:
As said, if you want to have a dynamic collection of things, use a List<T>. Internally, a List uses an array for storage too. That array has a fixed size just like any other array. Once an array is declared as having a size, it doesn't change. When you add an item to a List, it's added to the array. Initially, the List starts out with an array that I believe has a length of 16. When you try to add the 17th item to the List, what happens is that a new array is allocated, that's (I think) twice the size of the old one, so 32 items. Then the content of the old array is copied into the new array. So while a List may appear dynamic to the outside observer, internally it has to comply to the rules as well.
And as you might have guessed, the copying and allocation of the arrays isn't free so one should aim to have as few of those as possible and to do that you can specify (in the constructor of List) an initial size of the array, which in a perfect scenario is just big enough to hold everything you want. However, this is micro-optimization and it's unlikely it will ever matter to you, but it's always nice to know what you're actually doing.
You can create an array with the size set to a variable, i.e.
int size = 50;
string[] words = new string[size]; // contains 50 strings
However, that size can't change later on, if you decide you need 100 words. If you need the size to be really dynamic, you'll need to use a different sort of data structure. Try List.
Use an ArrayList if in .NET 1.x, or a List<yourtype> if in .NET 2.0 or 3.x.
Search for them in System.Collections and System.Collections.Generics.
You might also want to look into Dictionarys if your data is unique, This will give you two columns to work with.
User name , Total bill
it gives you a lot of built in tools to search and update just the value.
var yummy = new List<string>();
while(person.FeelsHappy()) {
yummy.Add(person.GetNewFavoriteFood());
}
Console.WriteLine("Sweet! I have a list of size {0}.", list.Count);
Console.WriteLine("I didn't even need to know how big to make it " +
"until I finished making it!");
try a generic list instead of array
In a nutshell, please use Collections and Generics.
It's a must for any C# developer, it's worth spending time to learn :)
As detailed above, the generic List<> is the best way of doing it.
If you're stuck in .NET 1.*, then you will have to use the ArrayList class instead. This does not have compile-time type checking and you also have to add casting - messy.
Successive versions have also implemented various variations - including thread safe variants.
If you really need to use an array instead of a list, then you can create an array whose size is calculated at run time like so...
e.g i want a two dimensional array of size n by n. n will be gotten at run time from the user
int n = 0;
bool isInteger = int.TryParse(Console.ReadLine(), out n);
var x = new int[n,n];