0

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?

MaYaN
  • 6,683
  • 12
  • 57
  • 109
  • Even in case of Random it will also be thread safe as isn't parallel LINQ query. So you can use Random in the same approach, and it depends on what random data you want - just bytes, or whole guids – Sergey Litvinov Oct 15 '15 at 13:33
  • Sergey, I was referring to the more general case of `sharing` a random object between different threads. you are right though. – MaYaN Oct 15 '15 at 13:35
  • When you have big different between `start` and `end` you need to generate and sort big collection – Alexander Oct 15 '15 at 13:45
  • @Alexander, that is not true, the nature of `LINQ` allows the values to be streamed, so no sorting or generation of a big collection, having said that, a new `Guid` is generated for each of the values in the resulting `Enumerable` which may not be ideal. – MaYaN Oct 15 '15 at 16:13
  • @MaYaN I don't think so. You cann't sort collection without knowledge about all it elements. Unfortunately I can't give proof link just now. – Alexander Oct 15 '15 at 16:18
  • @Alexander please take a look at the doc: https://msdn.microsoft.com/en-us/library/vstudio/bb534966(v=vs.100).aspx specifically saying: `This method is implemented by using deferred execution.` – MaYaN Oct 15 '15 at 16:20
  • @MaYaN yes it use deferred execution but not lazy evaluation (take a look [here](http://stackoverflow.com/questions/2530755/difference-between-deferred-execution-and-lazy-evaluation-in-c-sharp) for more details). You can easy try [this](http://rextester.com/XXQNNB68141) as an example. – Alexander Oct 15 '15 at 16:32
  • Deferred execution is still execution... And an OrderBy will always accumulate all values before it can sort anything. It is a very slow way to generate a large sequence. – H H Oct 15 '15 at 16:46

3 Answers3

2

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.

H H
  • 263,252
  • 30
  • 330
  • 514
  • @abelenky - I know. The answer applies to the distribution of the sorted values. – H H Oct 15 '15 at 13:51
  • _anything other than completely flat_ - and what if the Guids are generated in ascending order? – H H Oct 15 '15 at 14:12
2

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
abelenky
  • 63,815
  • 23
  • 109
  • 159
vanufryiuk
  • 21
  • 2
  • I am not looking for a `LINQ` interface replacement, I am very interested in knowing the pros/cons of using the approach in the question. Thanks for the answer anyway. – MaYaN Oct 15 '15 at 16:09
1

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.

abelenky
  • 63,815
  • 23
  • 109
  • 159
  • Very good observation, `Enumerable.Repeat` may provide a workaround/hack but using it in this case would be completely insane! – MaYaN Oct 15 '15 at 16:05